sysperfana/perfinvestigator/com.nokia.carbide.cpp.pi.call/src/com/nokia/carbide/cpp/pi/call/CallVisualiser.java
changeset 2 b9ab3b238396
child 5 844b047e260d
equal deleted inserted replaced
1:1050670c6980 2:b9ab3b238396
       
     1 /*
       
     2  * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). 
       
     3  * All rights reserved.
       
     4  * This component and the accompanying materials are made available
       
     5  * under the terms of the License "Eclipse Public License v1.0"
       
     6  * which accompanies this distribution, and is available
       
     7  * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8  *
       
     9  * Initial Contributors:
       
    10  * Nokia Corporation - initial contribution.
       
    11  *
       
    12  * Contributors:
       
    13  *
       
    14  * Description: 
       
    15  *
       
    16  */
       
    17 
       
    18 /**
       
    19  * 
       
    20  */
       
    21 package com.nokia.carbide.cpp.pi.call;
       
    22 
       
    23 //import java.awt.Color;
       
    24 import java.awt.Toolkit;
       
    25 import java.awt.datatransfer.Clipboard;
       
    26 import java.awt.datatransfer.StringSelection;
       
    27 import java.awt.event.MouseEvent;
       
    28 import java.text.DecimalFormat;
       
    29 import java.util.Vector;
       
    30 
       
    31 import org.eclipse.jface.action.Action;
       
    32 import org.eclipse.jface.action.ActionContributionItem;
       
    33 import org.eclipse.jface.action.IAction;
       
    34 import org.eclipse.jface.action.IContributionManager;
       
    35 import org.eclipse.jface.action.IMenuManager;
       
    36 import org.eclipse.jface.action.SubMenuManager;
       
    37 import org.eclipse.jface.viewers.ArrayContentProvider;
       
    38 import org.eclipse.jface.viewers.ITableLabelProvider;
       
    39 import org.eclipse.jface.viewers.LabelProvider;
       
    40 import org.eclipse.jface.viewers.TableViewer;
       
    41 import org.eclipse.jface.viewers.Viewer;
       
    42 import org.eclipse.jface.viewers.ViewerSorter;
       
    43 import org.eclipse.jface.wizard.Wizard;
       
    44 import org.eclipse.jface.wizard.WizardDialog;
       
    45 import org.eclipse.swt.SWT;
       
    46 import org.eclipse.swt.custom.SashForm;
       
    47 import org.eclipse.swt.events.FocusListener;
       
    48 import org.eclipse.swt.events.MouseListener;
       
    49 import org.eclipse.swt.events.SelectionAdapter;
       
    50 import org.eclipse.swt.events.SelectionEvent;
       
    51 import org.eclipse.swt.events.SelectionListener;
       
    52 import org.eclipse.swt.graphics.Image;
       
    53 import org.eclipse.swt.layout.GridData;
       
    54 import org.eclipse.swt.layout.GridLayout;
       
    55 import org.eclipse.swt.widgets.Composite;
       
    56 import org.eclipse.swt.widgets.Label;
       
    57 import org.eclipse.swt.widgets.Menu;
       
    58 import org.eclipse.swt.widgets.MenuItem;
       
    59 import org.eclipse.swt.widgets.Table;
       
    60 import org.eclipse.swt.widgets.TableColumn;
       
    61 import org.eclipse.swt.widgets.TableItem;
       
    62 import org.eclipse.ui.IActionBars;
       
    63 import org.eclipse.ui.PlatformUI;
       
    64 import org.eclipse.ui.actions.ActionFactory;
       
    65 import org.eclipse.ui.ide.IIDEActionConstants;
       
    66 
       
    67 import com.nokia.carbide.cpp.internal.pi.interfaces.ISaveSamples;
       
    68 import com.nokia.carbide.cpp.internal.pi.interfaces.ISaveTable;
       
    69 import com.nokia.carbide.cpp.internal.pi.save.SaveTableWizard;
       
    70 import com.nokia.carbide.cpp.internal.pi.visual.GenericTable;
       
    71 import com.nokia.carbide.cpp.pi.editors.PIPageEditor;
       
    72 import com.nokia.carbide.cpp.pi.util.SourceLookup;
       
    73 
       
    74 
       
    75 public class CallVisualiser extends GenericTable
       
    76 {
       
    77 	private static final long serialVersionUID = 1L;
       
    78 
       
    79 	// table column IDs in hopes it's quicker than comparing characters
       
    80 	protected static final int COLUMN_ID_IS_CALLED       = 100;
       
    81 	protected static final int COLUMN_ID_IS_CALLER       = 101;
       
    82 	protected static final int COLUMN_ID_RECURSIVE_CALL  = 102;
       
    83 	protected static final int COLUMN_ID_CALLER_PERCENT  = 103;
       
    84 	protected static final int COLUMN_ID_CALLEE_PERCENT  = 104;
       
    85 	protected static final int COLUMN_ID_IS_CALLED_COUNT = 105;
       
    86 	protected static final int COLUMN_ID_IS_CALLER_COUNT = 106;
       
    87 	
       
    88 	// table column headings
       
    89 	protected static final String COLUMN_HEAD_IS_CALLED       = Messages.getString("CallVisualiser.isCalled"); //$NON-NLS-1$
       
    90 	protected static final String COLUMN_HEAD_IS_CALLER       = Messages.getString("CallVisualiser.isCaller"); //$NON-NLS-1$
       
    91 	protected static final String COLUMN_HEAD_RECURSIVE_CALL  = Messages.getString("CallVisualiser.recursiveCaller"); //$NON-NLS-1$
       
    92 	protected static final String COLUMN_HEAD_CALLER_PERCENT  = Messages.getString("CallVisualiser.percentOfCalls"); //$NON-NLS-1$
       
    93 	protected static final String COLUMN_HEAD_CALLEE_PERCENT  = Messages.getString("CallVisualiser.percentOfCalls"); //$NON-NLS-1$
       
    94 	protected static final String COLUMN_HEAD_IS_CALLED_COUNT = Messages.getString("CallVisualiser.calledSamples"); //$NON-NLS-1$
       
    95 	protected static final String COLUMN_HEAD_IS_CALLER_COUNT = Messages.getString("CallVisualiser.callerSamples"); //$NON-NLS-1$
       
    96 	protected static final String COLUMN_HEAD_IS_CALLED_COUNT2 = Messages.getString("CallVisualiser.calls"); //$NON-NLS-1$
       
    97 	protected static final String COLUMN_HEAD_IS_CALLER_COUNT2 = Messages.getString("CallVisualiser.calls"); //$NON-NLS-1$
       
    98 
       
    99 	// table column widths
       
   100 	protected static final int COLUMN_WIDTH_IS_CALLED       = 70;
       
   101 	protected static final int COLUMN_WIDTH_IS_CALLER       = 70;
       
   102 	protected static final int COLUMN_WIDTH_RECURSIVE_CALL  = 105;
       
   103 	protected static final int COLUMN_WIDTH_CALLER_PERCENT  = 98;
       
   104 	protected static final int COLUMN_WIDTH_CALLEE_PERCENT  = 98;
       
   105 	protected static final int COLUMN_WIDTH_IS_CALLED_COUNT = 113;
       
   106 	protected static final int COLUMN_WIDTH_IS_CALLER_COUNT = 85;
       
   107 	protected static final int COLUMN_WIDTH_IS_CALLED_COUNT2 = 65;
       
   108 	protected static final int COLUMN_WIDTH_IS_CALLER_COUNT2 = 65;
       
   109 	
       
   110 	// SashForm to hold the tables and their titles
       
   111 	private SashForm sashForm;
       
   112 	
       
   113 	// Table viewers and their tables
       
   114 	private TableViewer callerTableViewer;
       
   115 	private Table callerTable;
       
   116 	
       
   117 	private TableViewer currentFunctionTableViewer;
       
   118 	private Table       currentFunctionTable;
       
   119 	private TableColumn  currentFunctionDefaultColumn;
       
   120 
       
   121 	private TableViewer calleeTableViewer;
       
   122 	private Table calleeTable;
       
   123 
       
   124 	// context menus
       
   125 	private Menu callerMenu;
       
   126 	private Menu currentFunctionMenu;
       
   127 	private Menu calleeMenu;
       
   128 	
       
   129 	private Table currentMenuTable;
       
   130 
       
   131 	private SashForm parent;
       
   132 
       
   133 	// this display's editor and page
       
   134 	private PIPageEditor pageEditor;
       
   135 	private int pageIndex;
       
   136 	
       
   137 	// trace associated with this display
       
   138 	private GfcTrace myTrace;
       
   139 	
       
   140 	// lists of functions, function callers, and function callees
       
   141 	private GfcFunctionItem[]  functionArray;
       
   142 	private CallerCalleeItem[] callerList;
       
   143 	private CallerCalleeItem[] calleeList;
       
   144 	
       
   145 	// menu items
       
   146 	protected Action copyAction;
       
   147 	protected Action copyTableAction;
       
   148 	protected Action functionCopyFunctionAction;
       
   149 	protected Action saveTableAction;
       
   150 	protected Action functionSaveFunctionAction;
       
   151 	
       
   152 	protected static int SAMPLES_AT_ONE_TIME = 1000;
       
   153 	
       
   154 	// class to pass sample data to the save wizard
       
   155     public class SaveSampleString implements ISaveSamples {
       
   156     	int startIndex = 0;
       
   157     	
       
   158     	public SaveSampleString() {
       
   159 		}
       
   160 
       
   161     	public String getData() {
       
   162     		return getData(SAMPLES_AT_ONE_TIME);
       
   163 		}
       
   164 
       
   165 		public String getData(int size) {
       
   166 			String returnString = getSampleString(this.startIndex, this.startIndex + size);
       
   167     		if (returnString == null)
       
   168     			this.startIndex = 0;
       
   169     		else
       
   170     			this.startIndex += size;
       
   171 			return returnString;
       
   172 		}
       
   173 
       
   174 		public int getIndex() {
       
   175 			return this.startIndex;
       
   176 		}
       
   177 
       
   178 		public void clear() {
       
   179 			this.startIndex = 0;
       
   180 		}
       
   181     }
       
   182 
       
   183 	/*
       
   184 	 * return the call samples selected in the interval 
       
   185 	 */
       
   186 	protected String getSampleString(int startIndex, int endIndex)
       
   187 	{
       
   188 		int startTime = (int) (PIPageEditor.currentPageEditor().getStartTime() * 1000.0 + 0.0005);
       
   189 		int endTime   = (int) (PIPageEditor.currentPageEditor().getEndTime()   * 1000.0 + 0.0005);
       
   190 		
       
   191 		// check if we have returned everything
       
   192 		if (startIndex > (endTime - startTime))
       
   193 			return null;
       
   194 		
       
   195 		GfcTrace trace = this.myTrace;
       
   196 		Vector samples = trace.samples;
       
   197 	
       
   198 		String returnString = ""; //$NON-NLS-1$
       
   199 		
       
   200 		if (startIndex == 0)
       
   201 			returnString = Messages.getString("CallVisualiser.callHeading"); //$NON-NLS-1$
       
   202 
       
   203 		for (int i = startTime + startIndex; i < endTime && i < startTime + endIndex; i++) {
       
   204 			GfcSample sample = (GfcSample) samples.get(i);
       
   205 
       
   206 			returnString +=   sample.sampleSynchTime + ",0x" //$NON-NLS-1$
       
   207 							+ Long.toHexString(sample.linkRegister)
       
   208 							+ ",\"" //$NON-NLS-1$
       
   209 							+ (sample.callerFunctionItt != null
       
   210 								? sample.callerFunctionItt.functionName
       
   211 								: sample.callerFunctionSym.functionName)
       
   212 							+ "\"," //$NON-NLS-1$
       
   213 							+ (sample.callerFunctionItt != null
       
   214 								? sample.callerFunctionItt.functionBinary.binaryName
       
   215 								: sample.callerFunctionSym.functionBinary.binaryName)
       
   216 							+ ",0x" //$NON-NLS-1$
       
   217 							+ Long.toHexString(sample.programCounter)
       
   218 							+ ",\"" //$NON-NLS-1$
       
   219 							+ (sample.currentFunctionItt != null
       
   220 								? sample.currentFunctionItt.functionName
       
   221 								: sample.currentFunctionSym.functionName)
       
   222 							+ "\"," //$NON-NLS-1$
       
   223 							+ (sample.currentFunctionItt != null
       
   224 								? sample.currentFunctionItt.functionBinary.binaryName
       
   225 								: sample.currentFunctionSym.functionBinary.binaryName)
       
   226 							+ "\n"; //$NON-NLS-1$
       
   227 		}
       
   228 
       
   229 		return returnString;
       
   230 	}
       
   231 
       
   232 	protected MenuItem getSaveSamplesItem(Menu menu, boolean enabled) {
       
   233 	    MenuItem saveSamplesItem = new MenuItem(menu, SWT.PUSH);
       
   234 
       
   235 		saveSamplesItem.setText(Messages.getString("CallVisualiser.saveAllSamplesForInterval")); //$NON-NLS-1$
       
   236 		saveSamplesItem.setEnabled(enabled);
       
   237 		
       
   238 		if (enabled) {
       
   239 			saveSamplesItem.addSelectionListener(new SelectionAdapter() { 
       
   240 				public void widgetSelected(SelectionEvent e) {
       
   241 					action("saveSamples"); //$NON-NLS-1$
       
   242 				}
       
   243 			});
       
   244 		}
       
   245 	
       
   246 		return saveSamplesItem;
       
   247 	}
       
   248 
       
   249 	public CallVisualiser(PIPageEditor pageEditor, int pageIndex, SashForm parent, GfcTrace trace)
       
   250 	{
       
   251 		this.pageEditor = pageEditor;
       
   252 		this.pageIndex  = pageIndex;
       
   253 		this.parent     = parent;
       
   254 		this.myTrace    = trace;
       
   255 		
       
   256 		// let the trace know about the CallVisualiser so that unit tests can find it
       
   257 		trace.setCallVisualiser(this);
       
   258 
       
   259 		// create the 3 table viewers: caller functions, selected function, callee functions
       
   260 		createTableViewers(parent);
       
   261 	}
       
   262 
       
   263 	public void createTableViewers(SashForm parent)
       
   264 	{
       
   265 		if (parent == null)
       
   266 			return;
       
   267 
       
   268 		/*
       
   269 		 * Create a SashForm with three labeled tables:
       
   270 		 * 
       
   271 		 * 1. Functions called by
       
   272 		 * 2. Functions (one checkbox selectable at a time)
       
   273 		 * 3. Functions called
       
   274 		 */
       
   275 
       
   276 		// the 3 tables will be in a sashForm
       
   277 		if (parent.getOrientation() != SWT.VERTICAL)
       
   278 		{
       
   279 			// put a SashForm in the SashForm
       
   280 			this.sashForm = new SashForm(parent, SWT.VERTICAL);
       
   281 			this.sashForm.SASH_WIDTH = 5; // 5 pixel wide sash
       
   282 		} else
       
   283 			this.sashForm = parent;
       
   284 		
       
   285 		createCallerTableViewer(sashForm);
       
   286 		createCurrentFunctionTableViewer(sashForm);
       
   287 		createCalleeTableViewer(sashForm);
       
   288 
       
   289 		createDefaultActions(true);
       
   290 	}
       
   291 	
       
   292 	private void createCurrentFunctionTableViewer(SashForm sashForm)
       
   293 	{
       
   294 		/*
       
   295 		 * Functions (one checkbox selectable at a time)
       
   296 		 *
       
   297 		 * 		selected checkbox
       
   298 		 *		percent load
       
   299 		 *  	function name
       
   300 		 *		function start address
       
   301 		 *		binary containing function
       
   302 		 *		sample count
       
   303 		 */
       
   304 		Label label;
       
   305 		Composite holder;
       
   306 		Table table;
       
   307 		TableColumn column;
       
   308 		
       
   309 		// middle functionTable and title
       
   310 		holder = new Composite(sashForm, SWT.NONE);
       
   311 		GridLayout gridLayout = new GridLayout(1, true);
       
   312 		gridLayout.marginWidth = 0;
       
   313 		gridLayout.marginHeight = 0;
       
   314 		holder.setLayout(gridLayout);
       
   315 
       
   316 		label = new Label(holder, SWT.CENTER | SWT.BORDER);
       
   317 		label.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_YELLOW));
       
   318 		label.setFont(PIPageEditor.helvetica_10);
       
   319 		label.setText(Messages.getString("CallVisualiser.selectFunction")); //$NON-NLS-1$
       
   320 		label.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
       
   321 
       
   322 		this.currentFunctionTableViewer = new TableViewer(holder,
       
   323   				SWT.BORDER | SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION);
       
   324 		this.currentFunctionTable = currentFunctionTableViewer.getTable();
       
   325 		
       
   326 		// add the label provider and content provider
       
   327 		this.currentFunctionTableViewer.setLabelProvider(new SharedLabelProvider(this.currentFunctionTable));
       
   328 		this.currentFunctionTableViewer.setContentProvider(new ArrayContentProvider());
       
   329 		this.currentFunctionTableViewer.setSorter(new SharedSorter());
       
   330 		
       
   331 		table = this.currentFunctionTable;
       
   332 		table.setRedraw(false);
       
   333 
       
   334 		// give the table a heading for use in copying and exported
       
   335 		table.setData(Messages.getString("CallVisualiser.selectedFunction")); //$NON-NLS-1$
       
   336 		
       
   337 		// create the other table entries when a row in this table is selected
       
   338 		table.addSelectionListener(new SelectionListener() {
       
   339 
       
   340 			public void widgetSelected(SelectionEvent event) {
       
   341 
       
   342 				if (!(event.item instanceof TableItem))
       
   343 					return;
       
   344 				
       
   345 	       		// set the other tables based on this selection
       
   346 	       		if (!(event.item.getData() instanceof GfcFunctionItem))
       
   347 	       			return;
       
   348 	       		
       
   349 	       		updateCallerCalleeTables((GfcFunctionItem)event.item.getData());
       
   350 			}
       
   351 
       
   352 			public void widgetDefaultSelected(SelectionEvent e) {
       
   353 				widgetSelected(e);
       
   354 			}});
       
   355 		
       
   356 		// data associated with the TableViewer will note which columns contain hex values
       
   357 		// Keep this in the order in which columns have been created
       
   358 		boolean[] isHex = {false, false, false, true, false, false, false};
       
   359 		this.currentFunctionTable.setData("isHex", isHex); //$NON-NLS-1$
       
   360 
       
   361 		// is called percent column
       
   362 		column = new TableColumn(table, SWT.RIGHT);
       
   363 		column.setText(COLUMN_HEAD_IS_CALLED);
       
   364 		column.setWidth(COLUMN_WIDTH_IS_CALLED);
       
   365 		column.setData(new Integer(COLUMN_ID_IS_CALLED));
       
   366 		column.setMoveable(true);
       
   367 		column.setResizable(true);
       
   368 		column.addSelectionListener(new CheckboxColumnSelectionHandler());
       
   369 
       
   370 		// is caller percent column
       
   371 		column = new TableColumn(table, SWT.RIGHT);
       
   372 		column.setText(COLUMN_HEAD_IS_CALLER);
       
   373 		column.setWidth(COLUMN_WIDTH_IS_CALLER);
       
   374 		column.setData(new Integer(COLUMN_ID_IS_CALLER));
       
   375 		column.setMoveable(true);
       
   376 		column.setResizable(true);
       
   377 		column.addSelectionListener(new CheckboxColumnSelectionHandler());
       
   378 
       
   379 		// function name column
       
   380 		column = new TableColumn(table, SWT.LEFT);
       
   381 		column.setText(COLUMN_HEAD_FUNCTION);
       
   382 		column.setWidth(COLUMN_WIDTH_FUNCTION_NAME);
       
   383 		column.setData(new Integer(COLUMN_ID_FUNCTION));
       
   384 		column.setMoveable(true);
       
   385 		column.setResizable(true);
       
   386 		column.addSelectionListener(new CheckboxColumnSelectionHandler());
       
   387 
       
   388 		// function start address column
       
   389 		column = new TableColumn(table, SWT.CENTER);
       
   390 		column.setText(COLUMN_HEAD_START_ADDR);
       
   391 		column.setWidth(COLUMN_WIDTH_START_ADDRESS);
       
   392 		column.setData(new Integer(COLUMN_ID_START_ADDR));
       
   393 		column.setMoveable(true);
       
   394 		column.setResizable(true);
       
   395 		column.addSelectionListener(new CheckboxColumnSelectionHandler());
       
   396 
       
   397 		// binary containing function column
       
   398 		column = new TableColumn(table, SWT.LEFT);
       
   399 		column.setText(COLUMN_HEAD_IN_BINARY);
       
   400 		column.setWidth(COLUMN_WIDTH_IN_BINARY);
       
   401 		column.setData(new Integer(COLUMN_ID_IN_BINARY));
       
   402 		column.setMoveable(true);
       
   403 		column.setResizable(true);
       
   404 		column.addSelectionListener(new CheckboxColumnSelectionHandler());
       
   405 
       
   406 		// path to binary containing function column
       
   407 		column = new TableColumn(table, SWT.LEFT);
       
   408 		column.setText(COLUMN_HEAD_IN_BINARY_PATH);
       
   409 		column.setWidth(COLUMN_WIDTH_IN_BINARY_PATH);
       
   410 		column.setData(new Integer(COLUMN_ID_IN_BINARY_PATH));
       
   411 		column.setMoveable(true);
       
   412 		column.setResizable(true);
       
   413 		column.addSelectionListener(new CheckboxColumnSelectionHandler());
       
   414 
       
   415 		// sample count column
       
   416 		column = new TableColumn(table, SWT.CENTER);
       
   417 		column.setText(COLUMN_HEAD_IS_CALLED_COUNT);
       
   418 		column.setWidth(COLUMN_WIDTH_IS_CALLED_COUNT);
       
   419 		column.setData(new Integer(COLUMN_ID_IS_CALLED_COUNT));
       
   420 		column.setMoveable(true);
       
   421 		column.setResizable(true);
       
   422 		column.addSelectionListener(new CheckboxColumnSelectionHandler());
       
   423 
       
   424 		// set the default sort column to COLUMN_ID_IS_CALLED_COUNT
       
   425 		currentFunctionDefaultColumn = column;
       
   426 
       
   427 		// sample count column
       
   428 		column = new TableColumn(table, SWT.CENTER);
       
   429 		column.setText(COLUMN_HEAD_IS_CALLER_COUNT);
       
   430 		column.setWidth(COLUMN_WIDTH_IS_CALLER_COUNT);
       
   431 		column.setData(new Integer(COLUMN_ID_IS_CALLER_COUNT));
       
   432 		column.setMoveable(true);
       
   433 		column.setResizable(true);
       
   434 		column.addSelectionListener(new CheckboxColumnSelectionHandler());
       
   435 
       
   436 		table.setLayoutData(new GridData(GridData.FILL_BOTH));
       
   437 		table.setHeaderVisible(true);
       
   438 		table.setLinesVisible(true);
       
   439 		table.setRedraw(true);
       
   440 
       
   441 		// listen for mouse clicks: to select a row, pop up a menu, etc.
       
   442 		table.addMouseListener(new CurrentFunctionMouseListener());
       
   443 
       
   444 		table.addFocusListener(new FocusListener() {
       
   445 			IAction oldCopyAction = null;
       
   446 
       
   447 			public void focusGained(org.eclipse.swt.events.FocusEvent arg0) {
       
   448 				IActionBars bars = PIPageEditor.getActionBars();
       
   449 				
       
   450 				// modify what is executed when Copy is called from the Edit menu
       
   451 				oldCopyAction = bars.getGlobalActionHandler(ActionFactory.COPY.getId());
       
   452 
       
   453 				bars.setGlobalActionHandler(ActionFactory.COPY.getId(), copyAction);
       
   454 
       
   455 				copyAction.setEnabled(currentFunctionTable.getSelectionCount() > 0);
       
   456 				bars.updateActionBars();
       
   457 				
       
   458 				// add to the Edit menu
       
   459 		        IMenuManager editMenuManager = bars.getMenuManager().findMenuUsingPath(IIDEActionConstants.M_EDIT);
       
   460 
       
   461 		        if (editMenuManager instanceof SubMenuManager)
       
   462 		        {
       
   463 		        	IContributionManager editManager = ((SubMenuManager)editMenuManager).getParent();
       
   464 		        	ActionContributionItem item;
       
   465 
       
   466 					editMenuManager.remove("PICopyFunction"); //$NON-NLS-1$
       
   467 					functionCopyFunctionAction.setEnabled(currentFunctionTable.getSelectionCount() > 0);
       
   468 		        	item = new ActionContributionItem(functionCopyFunctionAction);
       
   469 		        	item.setVisible(true);
       
   470 		        	editManager.prependToGroup(IIDEActionConstants.CUT_EXT, item);
       
   471 
       
   472 					editMenuManager.remove("PICopyTable"); //$NON-NLS-1$
       
   473 					copyTableAction.setEnabled(currentFunctionTable.getItemCount() > 0);
       
   474 		        	item = new ActionContributionItem(copyTableAction);
       
   475 		        	item.setVisible(true);
       
   476 		        	editManager.prependToGroup(IIDEActionConstants.CUT_EXT, item);
       
   477 		        }
       
   478 				
       
   479 				// add to the File menu
       
   480 		        IMenuManager fileMenuManager = bars.getMenuManager().findMenuUsingPath(IIDEActionConstants.M_FILE);
       
   481 
       
   482 		        if (fileMenuManager instanceof SubMenuManager)
       
   483 		        {
       
   484 		        	IContributionManager fileManager = ((SubMenuManager)fileMenuManager).getParent();
       
   485 		        	ActionContributionItem item;
       
   486 
       
   487 					fileMenuManager.remove("PISaveTable"); //$NON-NLS-1$
       
   488 					saveTableAction.setEnabled(currentFunctionTable.getItemCount() > 0);
       
   489 		        	item = new ActionContributionItem(saveTableAction);
       
   490 		        	item.setVisible(true);
       
   491 		        	fileManager.insertAfter("saveAll", item); //$NON-NLS-1$
       
   492 
       
   493 					fileMenuManager.remove("PISaveFunction"); //$NON-NLS-1$
       
   494 					functionSaveFunctionAction.setEnabled(currentFunctionTable.getSelectionCount() > 0);
       
   495 		        	item = new ActionContributionItem(functionSaveFunctionAction);
       
   496 		        	item.setVisible(true);
       
   497 		        	fileManager.insertAfter("PISaveTable", item); //$NON-NLS-1$
       
   498 		        }
       
   499 		}
       
   500 
       
   501 			public void focusLost(org.eclipse.swt.events.FocusEvent arg0) {
       
   502 				IActionBars bars = PIPageEditor.getActionBars();
       
   503 				bars.setGlobalActionHandler(ActionFactory.COPY.getId(), oldCopyAction);
       
   504 				bars.updateActionBars();
       
   505 
       
   506 				SubMenuManager editMenuManager = (SubMenuManager) PIPageEditor.getMenuManager().find(IIDEActionConstants.M_EDIT);
       
   507 				editMenuManager.remove("PICopyTable"); //$NON-NLS-1$
       
   508 				editMenuManager.remove("PICopyFunction"); //$NON-NLS-1$
       
   509 
       
   510 				SubMenuManager fileMenuManager = (SubMenuManager) PIPageEditor.getMenuManager().find(IIDEActionConstants.M_FILE);
       
   511 				fileMenuManager.remove("PISaveTable"); //$NON-NLS-1$
       
   512 				fileMenuManager.remove("PISaveFunction"); //$NON-NLS-1$
       
   513 			}
       
   514 		});
       
   515 	}
       
   516 	
       
   517 	private void createCallerTableViewer(SashForm sashForm)
       
   518 	{
       
   519 		/*
       
   520 		 * Functions called by
       
   521 		 * 
       
   522 		 *		percent of calls
       
   523 		 *		total percent
       
   524 		 *		caller percent
       
   525 		 *  	function name
       
   526 		 *		function start address
       
   527 		 *		binary containing function
       
   528 		 *		sample count
       
   529 		 */
       
   530 		Label label;
       
   531 		Composite holder;
       
   532 		Table table;
       
   533 		TableColumn column;
       
   534 		
       
   535 		// top functionTable and title
       
   536 		holder = new Composite(sashForm, SWT.NONE);
       
   537 //		holder.setLayout(new FillLayout(SWT.VERTICAL));
       
   538 		GridLayout gridLayout = new GridLayout(1, true);
       
   539 		gridLayout.marginWidth = 0;
       
   540 		gridLayout.marginHeight = 0;
       
   541 		holder.setLayout(gridLayout);
       
   542 
       
   543 		label = new Label(holder, SWT.CENTER | SWT.BORDER);
       
   544 		label.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_CYAN));
       
   545 		label.setFont(PIPageEditor.helvetica_10);
       
   546 		label.setText(Messages.getString("CallVisualiser.callingSelectedFunction")); //$NON-NLS-1$
       
   547 		label.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
       
   548 
       
   549 		this.callerTableViewer = new TableViewer(holder,
       
   550   				SWT.BORDER | SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION);
       
   551 		this.callerTable = callerTableViewer.getTable();
       
   552 		
       
   553 		// add the label provider and content provider
       
   554 		this.callerTableViewer.setLabelProvider(new SharedLabelProvider(this.callerTable));
       
   555 		this.callerTableViewer.setContentProvider(new ArrayContentProvider());
       
   556 		this.callerTableViewer.setSorter(new SharedSorter());
       
   557 
       
   558 		table = this.callerTable;
       
   559 		table.setRedraw(false);
       
   560 
       
   561 		// give the table a heading for possible use in copying and exported
       
   562 		table.setData(Messages.getString("CallVisualiser.callerFunctions")); //$NON-NLS-1$
       
   563 		
       
   564 		// data associated with the TableViewer will note which columns contain hex values
       
   565 		// Keep this in the order in which columns have been created
       
   566 		boolean[] isHex = {false, false, false, true, false, false, false};
       
   567 		this.callerTable.setData("isHex", isHex); //$NON-NLS-1$
       
   568 
       
   569 		// percent of calls column
       
   570 		column = new TableColumn(table, SWT.RIGHT);
       
   571 		column.setText(COLUMN_HEAD_CALLER_PERCENT);
       
   572 		column.setWidth(COLUMN_WIDTH_CALLER_PERCENT);
       
   573 		column.setData(new Integer(COLUMN_ID_CALLER_PERCENT));
       
   574 		column.setMoveable(true);
       
   575 		column.setResizable(true);
       
   576 		column.addSelectionListener(new CalledByColumnSelectionHandler());
       
   577 
       
   578 		// sample count column
       
   579 		column = new TableColumn(table, SWT.CENTER);
       
   580 		column.setText(COLUMN_HEAD_IS_CALLER_COUNT2);
       
   581 		column.setWidth(COLUMN_WIDTH_IS_CALLER_COUNT2);
       
   582 		column.setData(new Integer(COLUMN_ID_IS_CALLER_COUNT));
       
   583 		column.setMoveable(true);
       
   584 		column.setResizable(true);
       
   585 		column.addSelectionListener(new CalledByColumnSelectionHandler());
       
   586 
       
   587 		// function name column
       
   588 		column = new TableColumn(table, SWT.LEFT);
       
   589 		column.setText(COLUMN_HEAD_FUNCTION);
       
   590 		column.setWidth(COLUMN_WIDTH_FUNCTION_NAME);
       
   591 		column.setData(new Integer(COLUMN_ID_FUNCTION));
       
   592 		column.setMoveable(true);
       
   593 		column.setResizable(true);
       
   594 		column.addSelectionListener(new CalledByColumnSelectionHandler());
       
   595 
       
   596 		// function start address column
       
   597 		column = new TableColumn(table, SWT.CENTER);
       
   598 		column.setText(COLUMN_HEAD_START_ADDR);
       
   599 		column.setWidth(COLUMN_WIDTH_START_ADDRESS);
       
   600 		column.setData(new Integer(COLUMN_ID_START_ADDR));
       
   601 		column.setMoveable(true);
       
   602 		column.setResizable(true);
       
   603 		column.addSelectionListener(new CalledByColumnSelectionHandler());
       
   604 
       
   605 		// binary containing function column
       
   606 		column = new TableColumn(table, SWT.LEFT);
       
   607 		column.setText(COLUMN_HEAD_IN_BINARY);
       
   608 		column.setWidth(COLUMN_WIDTH_IN_BINARY);
       
   609 		column.setData(new Integer(COLUMN_ID_IN_BINARY));
       
   610 		column.setMoveable(true);
       
   611 		column.setResizable(true);
       
   612 		column.addSelectionListener(new CalledByColumnSelectionHandler());
       
   613 
       
   614 		// path to binary containing function column
       
   615 		column = new TableColumn(table, SWT.LEFT);
       
   616 		column.setText(COLUMN_HEAD_IN_BINARY_PATH);
       
   617 		column.setWidth(COLUMN_WIDTH_IN_BINARY_PATH);
       
   618 		column.setData(new Integer(COLUMN_ID_IN_BINARY_PATH));
       
   619 		column.setMoveable(true);
       
   620 		column.setResizable(true);
       
   621 		column.addSelectionListener(new CalledByColumnSelectionHandler());
       
   622 
       
   623 		// is caller percent column
       
   624 		column = new TableColumn(table, SWT.RIGHT);
       
   625 		column.setText(COLUMN_HEAD_IS_CALLER);
       
   626 		column.setWidth(COLUMN_WIDTH_IS_CALLER);
       
   627 		column.setData(new Integer(COLUMN_ID_IS_CALLER));
       
   628 		column.setMoveable(true);
       
   629 		column.setResizable(true);
       
   630 		column.addSelectionListener(new CalledByColumnSelectionHandler());
       
   631 
       
   632 		table.setLayoutData(new GridData(GridData.FILL_BOTH));
       
   633 //		table.setLayout(new FillLayout());
       
   634 		table.setHeaderVisible(true);
       
   635 		table.setLinesVisible(true);
       
   636 		table.setRedraw(true);
       
   637 		
       
   638 		// when a row is selected, allow the user to double-click or right click and make that function the selected function
       
   639 		table.addSelectionListener(new SelectionAdapter() {
       
   640 
       
   641 			public void widgetDefaultSelected(SelectionEvent se) {
       
   642 				TableItem item = (TableItem)se.item;
       
   643 				Table table = (Table)se.widget;
       
   644 				CallerCalleeItem callerCalleeItem = (CallerCalleeItem)item.getData();
       
   645 				
       
   646 				// deselect this line
       
   647 				table.deselectAll();
       
   648 				
       
   649 				// choose this row's function
       
   650 				chooseNewFunction(callerCalleeItem);
       
   651 			}
       
   652 		});
       
   653 		
       
   654 		table.addMouseListener(new CallerMouseListener());
       
   655 		
       
   656 		table.addFocusListener(new FocusListener() {
       
   657 			IAction oldCopyAction = null;
       
   658 
       
   659 			public void focusGained(org.eclipse.swt.events.FocusEvent arg0) {
       
   660 				IActionBars bars = PIPageEditor.getActionBars();
       
   661 				
       
   662 				// modify what is executed when Copy is called from the Edit menu
       
   663 				oldCopyAction = bars.getGlobalActionHandler(ActionFactory.COPY.getId());
       
   664 
       
   665 				bars.setGlobalActionHandler(ActionFactory.COPY.getId(), copyAction);
       
   666 
       
   667 				copyAction.setEnabled(callerTable.getSelectionCount() > 0);
       
   668 				bars.updateActionBars();
       
   669 				
       
   670 				// add to the Edit menu
       
   671 		        IMenuManager editMenuManager = bars.getMenuManager().findMenuUsingPath(IIDEActionConstants.M_EDIT);
       
   672 
       
   673 		        if (editMenuManager instanceof SubMenuManager)
       
   674 		        {
       
   675 		        	IContributionManager editManager = ((SubMenuManager)editMenuManager).getParent();
       
   676 		        	ActionContributionItem item;
       
   677 
       
   678 					editMenuManager.remove("PICopyTable"); //$NON-NLS-1$
       
   679 					copyTableAction.setEnabled(callerTable.getItemCount() > 0);
       
   680 		        	item = new ActionContributionItem(copyTableAction);
       
   681 		        	item.setVisible(true);
       
   682 		        	editManager.prependToGroup(IIDEActionConstants.CUT_EXT, item);
       
   683 		        }
       
   684 				
       
   685 				// add to the File menu
       
   686 		        IMenuManager fileMenuManager = bars.getMenuManager().findMenuUsingPath(IIDEActionConstants.M_FILE);
       
   687 
       
   688 		        if (fileMenuManager instanceof SubMenuManager)
       
   689 		        {
       
   690 		        	IContributionManager fileManager = ((SubMenuManager)fileMenuManager).getParent();
       
   691 		        	ActionContributionItem item;
       
   692 
       
   693 					fileMenuManager.remove("PISaveTable"); //$NON-NLS-1$
       
   694 					saveTableAction.setEnabled(callerTable.getItemCount() > 0);
       
   695 		        	item = new ActionContributionItem(saveTableAction);
       
   696 		        	item.setVisible(true);
       
   697 		        	fileManager.insertAfter("saveAll", item); //$NON-NLS-1$
       
   698 		        }
       
   699 			}
       
   700 
       
   701 			public void focusLost(org.eclipse.swt.events.FocusEvent arg0) {
       
   702 				IActionBars bars = PIPageEditor.getActionBars();
       
   703 				bars.setGlobalActionHandler(ActionFactory.COPY.getId(), oldCopyAction);
       
   704 				bars.updateActionBars();
       
   705 
       
   706 				SubMenuManager editMenuManager = (SubMenuManager) PIPageEditor.getMenuManager().find(IIDEActionConstants.M_EDIT);
       
   707 				editMenuManager.remove("PICopyTable"); //$NON-NLS-1$
       
   708 
       
   709 				SubMenuManager fileMenuManager = (SubMenuManager) PIPageEditor.getMenuManager().find(IIDEActionConstants.M_FILE);
       
   710 				fileMenuManager.remove("PISaveTable"); //$NON-NLS-1$
       
   711 			}
       
   712 		});
       
   713 	}
       
   714 	
       
   715 	private void createCalleeTableViewer(SashForm sashForm)
       
   716 	{
       
   717 		/*
       
   718 		 * Functions called
       
   719 		 * 
       
   720 		 *		percent of calls
       
   721 		 *		total percent
       
   722 		 *		caller percent
       
   723 		 *  	function name
       
   724 		 *		function start address
       
   725 		 *		binary containing function
       
   726 		 *		sample count
       
   727 		 */
       
   728 		Label label;
       
   729 		Composite holder;
       
   730 		Table table;
       
   731 		TableColumn column;
       
   732 		
       
   733 		// bottom functionTable and title
       
   734 		holder = new Composite(sashForm, SWT.NONE);
       
   735 //		holder.setLayout(new FillLayout(SWT.VERTICAL));
       
   736 		GridLayout gridLayout = new GridLayout(1, true);
       
   737 		gridLayout.marginWidth = 0;
       
   738 		gridLayout.marginHeight = 0;
       
   739 		holder.setLayout(gridLayout);
       
   740 
       
   741 		label = new Label(holder, SWT.CENTER | SWT.BORDER);
       
   742 		label.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_CYAN));
       
   743 		label.setFont(PIPageEditor.helvetica_10);
       
   744 		label.setText(Messages.getString("CallVisualiser.calledBySelectedFunction")); //$NON-NLS-1$
       
   745 		label.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
       
   746 
       
   747 		this.calleeTableViewer = new TableViewer(holder,
       
   748   				SWT.BORDER | SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION);
       
   749 		this.calleeTable = calleeTableViewer.getTable();
       
   750 		
       
   751 		// add the label provider and content provider
       
   752 		this.calleeTableViewer.setLabelProvider(new SharedLabelProvider(this.calleeTable));
       
   753 		this.calleeTableViewer.setContentProvider(new ArrayContentProvider());
       
   754 		this.calleeTableViewer.setSorter(new SharedSorter());
       
   755 
       
   756 		table = this.calleeTable;
       
   757 		table.setRedraw(false);
       
   758 
       
   759 		// give the table a heading for possible use in copying and exported
       
   760 		table.setData(Messages.getString("CallVisualiser.calleeFunctions")); //$NON-NLS-1$
       
   761 		
       
   762 		// data associated with the TableViewer will note which columns contain hex values
       
   763 		// Keep this in the order in which columns have been created
       
   764 		boolean[] isHex = {false, false, false, true, false, false, false};
       
   765 		this.calleeTable.setData("isHex", isHex); //$NON-NLS-1$
       
   766 		
       
   767 		// percent of calls column
       
   768 		column = new TableColumn(table, SWT.RIGHT);
       
   769 		column.setText(COLUMN_HEAD_CALLEE_PERCENT);
       
   770 		column.setWidth(COLUMN_WIDTH_CALLEE_PERCENT);
       
   771 		column.setData(new Integer(COLUMN_ID_CALLEE_PERCENT));
       
   772 		column.setMoveable(true);
       
   773 		column.setResizable(true);
       
   774 		column.addSelectionListener(new CalledColumnSelectionHandler());
       
   775 
       
   776 		// sample count column
       
   777 		column = new TableColumn(table, SWT.CENTER);
       
   778 		column.setText(COLUMN_HEAD_IS_CALLED_COUNT2);
       
   779 		column.setWidth(COLUMN_WIDTH_IS_CALLED_COUNT2);
       
   780 		column.setData(new Integer(COLUMN_ID_IS_CALLED_COUNT));
       
   781 		column.setMoveable(true);
       
   782 		column.setResizable(true);
       
   783 		column.addSelectionListener(new CalledColumnSelectionHandler());
       
   784 
       
   785 		// function name column
       
   786 		column = new TableColumn(table, SWT.LEFT);
       
   787 		column.setText(COLUMN_HEAD_FUNCTION);
       
   788 		column.setWidth(COLUMN_WIDTH_FUNCTION_NAME);
       
   789 		column.setData(new Integer(COLUMN_ID_FUNCTION));
       
   790 		column.setMoveable(true);
       
   791 		column.setResizable(true);
       
   792 		column.addSelectionListener(new CalledColumnSelectionHandler());
       
   793 
       
   794 		// function start address column
       
   795 		column = new TableColumn(table, SWT.CENTER);
       
   796 		column.setText(COLUMN_HEAD_START_ADDR);
       
   797 		column.setWidth(COLUMN_WIDTH_START_ADDRESS);
       
   798 //		column.setData(new Integer(COLUMN_ID_START_ADDR3));
       
   799 		column.setData(new Integer(COLUMN_ID_START_ADDR));
       
   800 		column.setMoveable(true);
       
   801 		column.setResizable(true);
       
   802 		column.addSelectionListener(new CalledColumnSelectionHandler());
       
   803 
       
   804 		// binary containing function column
       
   805 		column = new TableColumn(table, SWT.LEFT);
       
   806 		column.setText(COLUMN_HEAD_IN_BINARY);
       
   807 		column.setWidth(COLUMN_WIDTH_IN_BINARY);
       
   808 //		column.setData(new Integer(COLUMN_ID_IN_BINARY3));
       
   809 		column.setData(new Integer(COLUMN_ID_IN_BINARY));
       
   810 		column.setMoveable(true);
       
   811 		column.setResizable(true);
       
   812 		column.addSelectionListener(new CalledColumnSelectionHandler());
       
   813 
       
   814 		// path to binary containing function column
       
   815 		column = new TableColumn(table, SWT.LEFT);
       
   816 		column.setText(COLUMN_HEAD_IN_BINARY_PATH);
       
   817 		column.setWidth(COLUMN_WIDTH_IN_BINARY_PATH);
       
   818 //		column.setData(new Integer(COLUMN_ID_IN_BINARY_PATH3));
       
   819 		column.setData(new Integer(COLUMN_ID_IN_BINARY_PATH));
       
   820 		column.setMoveable(true);
       
   821 		column.setResizable(true);
       
   822 		column.addSelectionListener(new CalledColumnSelectionHandler());
       
   823 
       
   824 		// percent of calls column
       
   825 		column = new TableColumn(table, SWT.RIGHT);
       
   826 		column.setText(COLUMN_HEAD_IS_CALLED);
       
   827 		column.setWidth(COLUMN_WIDTH_IS_CALLED);
       
   828 //		column.setData(new Integer(COLUMN_ID_IS_CALLED3));
       
   829 		column.setData(new Integer(COLUMN_ID_IS_CALLED));
       
   830 		column.setMoveable(true);
       
   831 		column.setResizable(true);
       
   832 		column.addSelectionListener(new CalledColumnSelectionHandler());
       
   833 
       
   834 		table.setLayoutData(new GridData(GridData.FILL_BOTH));
       
   835 //		table.setLayout(new FillLayout());
       
   836 		table.setHeaderVisible(true);
       
   837 		table.setLinesVisible(true);
       
   838 		table.setRedraw(true);
       
   839 		
       
   840 		// when a row is selected, allow the user to double-click or right click and make that function the selected function
       
   841 		table.addSelectionListener(new SelectionAdapter() {
       
   842 
       
   843 			public void widgetDefaultSelected(SelectionEvent se) {
       
   844 				TableItem item = (TableItem)se.item;
       
   845 				Table table = (Table)se.widget;
       
   846 				CallerCalleeItem callerCallee = (CallerCalleeItem)item.getData();
       
   847 				
       
   848 				// deselect this row
       
   849 				table.deselectAll();
       
   850 				
       
   851 				// choose this row's function
       
   852 				chooseNewFunction(callerCallee);
       
   853 			}
       
   854 		});
       
   855 		
       
   856 		table.addMouseListener(new CalleeMouseListener());
       
   857 		
       
   858 		table.addFocusListener(new FocusListener() {
       
   859 			IAction oldCopyAction = null;
       
   860 
       
   861 			public void focusGained(org.eclipse.swt.events.FocusEvent arg0) {
       
   862 				IActionBars bars = PIPageEditor.getActionBars();
       
   863 				
       
   864 				// modify what is executed when Copy is called from the Edit menu
       
   865 				oldCopyAction = bars.getGlobalActionHandler(ActionFactory.COPY.getId());
       
   866 
       
   867 				bars.setGlobalActionHandler(ActionFactory.COPY.getId(), copyAction);
       
   868 
       
   869 				copyAction.setEnabled(calleeTable.getSelectionCount() > 0);
       
   870 				bars.updateActionBars();
       
   871 				
       
   872 				// add to the Edit menu
       
   873 		        IMenuManager editMenuManager = bars.getMenuManager().findMenuUsingPath(IIDEActionConstants.M_EDIT);
       
   874 
       
   875 		        if (editMenuManager instanceof SubMenuManager)
       
   876 		        {
       
   877 		        	IContributionManager editManager = ((SubMenuManager)editMenuManager).getParent();
       
   878 		        	ActionContributionItem item;
       
   879 
       
   880 					editMenuManager.remove("PICopyTable"); //$NON-NLS-1$
       
   881 					copyTableAction.setEnabled(calleeTable.getItemCount() > 0);
       
   882 		        	item = new ActionContributionItem(copyTableAction);
       
   883 		        	item.setVisible(true);
       
   884 		        	editManager.prependToGroup(IIDEActionConstants.CUT_EXT, item);
       
   885 		        }
       
   886 				
       
   887 				// add to the File menu
       
   888 		        IMenuManager fileMenuManager = bars.getMenuManager().findMenuUsingPath(IIDEActionConstants.M_FILE);
       
   889 
       
   890 		        if (fileMenuManager instanceof SubMenuManager)
       
   891 		        {
       
   892 		        	IContributionManager fileManager = ((SubMenuManager)fileMenuManager).getParent();
       
   893 		        	ActionContributionItem item;
       
   894 
       
   895 					fileMenuManager.remove("PISaveTable"); //$NON-NLS-1$
       
   896 					saveTableAction.setEnabled(calleeTable.getItemCount() > 0);
       
   897 		        	item = new ActionContributionItem(saveTableAction);
       
   898 		        	item.setVisible(true);
       
   899 		        	fileManager.insertAfter("saveAll", item); //$NON-NLS-1$
       
   900 		        }
       
   901 			}
       
   902 
       
   903 			public void focusLost(org.eclipse.swt.events.FocusEvent arg0) {
       
   904 				IActionBars bars = PIPageEditor.getActionBars();
       
   905 				bars.setGlobalActionHandler(ActionFactory.COPY.getId(), oldCopyAction);
       
   906 				bars.updateActionBars();
       
   907 
       
   908 				SubMenuManager editMenuManager = (SubMenuManager) PIPageEditor.getMenuManager().find(IIDEActionConstants.M_EDIT);
       
   909 				editMenuManager.remove("PICopyTable"); //$NON-NLS-1$
       
   910 
       
   911 				SubMenuManager fileMenuManager = (SubMenuManager) PIPageEditor.getMenuManager().find(IIDEActionConstants.M_FILE);
       
   912 				fileMenuManager.remove("PISaveTable"); //$NON-NLS-1$
       
   913 			}
       
   914 		});
       
   915 	}
       
   916 	
       
   917 	private void chooseNewFunction(CallerCalleeItem callerCalleeItem)
       
   918 	{
       
   919 		// find the correct line in the function table and select it
       
   920 		int count = currentFunctionTable.getItemCount();
       
   921 
       
   922 		for (int i = 0; i < count; i++) {
       
   923 			GfcFunctionItem functionItem = (GfcFunctionItem)(currentFunctionTable.getItem(i).getData());
       
   924 			if (   functionItem.name.equals(callerCalleeItem.item.name)
       
   925 				&& functionItem.dllName.equals(callerCalleeItem.item.dllName)) {
       
   926 				currentFunctionTable.select(i);
       
   927 				currentFunctionTable.showSelection();
       
   928 				updateCallerCalleeTables(functionItem);
       
   929 				return;
       
   930 			}
       
   931 		}
       
   932 	}
       
   933 
       
   934 	public void updateCallerCalleeTables(GfcFunctionItem item)
       
   935 	{
       
   936 		Table table;
       
   937 		TableColumn sortByColumn;
       
   938 
       
   939    		setCallerListToFunctionsThatCallThisFunction(item);
       
   940     	setCalleeListToFunctionsThisFunctionCalls(item);
       
   941     	
       
   942     	callerTableViewer.setInput(callerList);
       
   943 
       
   944     	if ((callerList != null) && (callerList.length > 0)) {
       
   945     		SharedSorter sorter = ((SharedSorter) callerTableViewer.getSorter());
       
   946     		int columnID = sorter.getColumnID();
       
   947     		
       
   948     		if (columnID == -1) {
       
   949     			columnID = COLUMN_ID_CALLER_PERCENT;
       
   950     		} else {
       
   951     			sorter.setSortAscending(!sorter.getSortAscending());
       
   952     		}
       
   953 			sorter.doSort(columnID);
       
   954  	
       
   955 	    	sortByColumn = null;
       
   956 	    	table = callerTableViewer.getTable();
       
   957 			for (int i = 0; i < table.getColumnCount(); i++) {
       
   958 				if (table.getColumn(i).getData() instanceof Integer) {
       
   959 					if (((Integer)table.getColumn(i).getData()) == columnID) {
       
   960 						sortByColumn = table.getColumn(i);
       
   961 						break;
       
   962 					}
       
   963 				}
       
   964 			}
       
   965 	
       
   966 			if (sortByColumn != null) {
       
   967 				table.setSortColumn(sortByColumn);
       
   968 				table.setSortDirection(sorter.getSortAscending() ? SWT.UP : SWT.DOWN);
       
   969 			}
       
   970 	    	callerTableViewer.refresh();
       
   971     	} else {
       
   972     		callerTableViewer.getTable().setSortColumn(null);
       
   973     	}
       
   974 
       
   975     	calleeTableViewer.setInput(calleeList);
       
   976 
       
   977     	if ((calleeList != null) && (calleeList.length > 0)) {
       
   978     		SharedSorter sorter = ((SharedSorter) calleeTableViewer.getSorter());
       
   979     		int columnID = sorter.getColumnID();
       
   980     		
       
   981     		if (columnID == -1) {
       
   982     			columnID = COLUMN_ID_CALLEE_PERCENT;
       
   983     		} else {
       
   984     			sorter.setSortAscending(!sorter.getSortAscending());
       
   985     		}
       
   986 			sorter.doSort(columnID);
       
   987 	
       
   988 	    	sortByColumn = null;
       
   989 	    	table = calleeTableViewer.getTable();
       
   990 			for (int i = 0; i < table.getColumnCount(); i++) {
       
   991 				if (table.getColumn(i).getData() instanceof Integer) {
       
   992 					if (((Integer)table.getColumn(i).getData()) == columnID) {
       
   993 						sortByColumn = table.getColumn(i);
       
   994 						break;
       
   995 					}
       
   996 				}
       
   997 			}
       
   998 	
       
   999 			if (sortByColumn != null) {
       
  1000 				table.setSortColumn(sortByColumn);
       
  1001 				table.setSortDirection(sorter.getSortAscending() ? SWT.UP : SWT.DOWN);
       
  1002 			}
       
  1003 			calleeTableViewer.refresh();
       
  1004     	} else {
       
  1005     		calleeTableViewer.getTable().setSortColumn(null);
       
  1006     	}
       
  1007 	}
       
  1008 	
       
  1009 	private class CallerMouseListener implements MouseListener
       
  1010 	{
       
  1011 		public void mouseDoubleClick(org.eclipse.swt.events.MouseEvent me) {}
       
  1012 
       
  1013 		public void mouseDown(org.eclipse.swt.events.MouseEvent me) {}
       
  1014 
       
  1015 		public void mouseUp(org.eclipse.swt.events.MouseEvent me) {
       
  1016 			copyAction.setEnabled(callerTable.getSelectionCount() > 0);
       
  1017 			copyTableAction.setEnabled(callerTable.getItemCount() > 0);
       
  1018 
       
  1019 			// only look for button 3 (right click)
       
  1020 			if (me.button != MouseEvent.BUTTON3)
       
  1021 				return;
       
  1022 
       
  1023 			// make the caller table the menu table
       
  1024 			currentMenuTable = callerTable;
       
  1025 
       
  1026 			if (callerMenu != null) {
       
  1027 				callerMenu.dispose();
       
  1028 			}
       
  1029 
       
  1030 			callerMenu = new Menu(callerTable.getShell(), SWT.POP_UP); 
       
  1031 			
       
  1032 			MenuItem showCallInfoItem = new MenuItem(callerMenu, SWT.PUSH);
       
  1033 			showCallInfoItem.setText(Messages.getString("CallVisualiser.showCallInfo")); //$NON-NLS-1$
       
  1034 			showCallInfoItem.addSelectionListener(new SelectionAdapter() { 
       
  1035 				public void widgetSelected(SelectionEvent se) {
       
  1036 				    // based on the table's selected item, update the tables
       
  1037 					TableItem[] selections = callerTable.getSelection();
       
  1038 					callerTable.deselectAll();
       
  1039 					
       
  1040 					if (selections.length != 0)
       
  1041 						chooseNewFunction((CallerCalleeItem)selections[0].getData());
       
  1042 				}
       
  1043 			});
       
  1044 			
       
  1045 			new MenuItem(callerMenu, SWT.SEPARATOR);
       
  1046 			
       
  1047 			MenuItem sourceLookupItem = new MenuItem(callerMenu, SWT.PUSH);
       
  1048 			sourceLookupItem.setText(Messages.getString("CallVisualiser.sourcelookup"));	//$NON-NLS-1$
       
  1049 			sourceLookupItem.addSelectionListener(new SelectionListener() {
       
  1050 
       
  1051 				public void widgetDefaultSelected(SelectionEvent arg0) {
       
  1052 				}
       
  1053 
       
  1054 				public void widgetSelected(SelectionEvent arg0) {
       
  1055 					doSourceLookup(callerTable);
       
  1056 				}
       
  1057 				
       
  1058 			});
       
  1059 
       
  1060 			if (callerTable.getSelectionCount() == 0) {
       
  1061 				showCallInfoItem.setEnabled(false);
       
  1062 				sourceLookupItem.setEnabled(false);
       
  1063 			}
       
  1064 
       
  1065 			// add copy, copy all, and save all
       
  1066 			new MenuItem(callerMenu, SWT.SEPARATOR);
       
  1067 			getCopyItem(callerMenu, callerTable.getSelectionCount() > 0);
       
  1068 			getCopyTableItem(callerMenu, callerTable.getItemCount() > 0);
       
  1069 			copyAction.setEnabled(callerTable.getSelectionCount() > 0);
       
  1070 			copyTableAction.setEnabled(callerTable.getItemCount() > 0);
       
  1071 
       
  1072 			new MenuItem(callerMenu, SWT.SEPARATOR);
       
  1073 			getSaveTableItem(callerMenu, callerTable.getItemCount() > 0);
       
  1074 			saveTableAction.setEnabled(callerTable.getItemCount() > 0);
       
  1075 			
       
  1076 			// save samples
       
  1077 			int startTime = (int) (PIPageEditor.currentPageEditor().getStartTime() * 1000.0f);
       
  1078 			int endTime   = (int) (PIPageEditor.currentPageEditor().getEndTime()   * 1000.0f);
       
  1079 
       
  1080 			if ((startTime == -1) || (endTime   == -1) || (startTime == endTime))
       
  1081 				getSaveSamplesItem(callerMenu, false); //$NON-NLS-1$
       
  1082 			else
       
  1083 				getSaveSamplesItem(callerMenu, true); //$NON-NLS-1$
       
  1084 			
       
  1085 			callerMenu.setLocation(callerTable.getParent().toDisplay(me.x, me.y));
       
  1086 			callerMenu.setVisible(true);
       
  1087 			callerTable.setMenu(callerMenu);
       
  1088 		}
       
  1089 	}
       
  1090 	
       
  1091 	private class CurrentFunctionMouseListener implements MouseListener
       
  1092 	{
       
  1093 		public void mouseDoubleClick(org.eclipse.swt.events.MouseEvent me) {}
       
  1094 
       
  1095 		public void mouseDown(org.eclipse.swt.events.MouseEvent me) {}
       
  1096 
       
  1097 		public void mouseUp(org.eclipse.swt.events.MouseEvent me) {
       
  1098 			copyAction.setEnabled(currentFunctionTable.getSelectionCount() > 0);
       
  1099 			copyTableAction.setEnabled(currentFunctionTable.getItemCount() > 0);
       
  1100 			functionCopyFunctionAction.setEnabled(currentFunctionTable.getSelectionCount() > 0);
       
  1101 
       
  1102 			// only look for button 3 (right click)
       
  1103 			if (me.button != MouseEvent.BUTTON3)
       
  1104 				return;
       
  1105 
       
  1106 			// make the current function table the menu table
       
  1107 			currentMenuTable = currentFunctionTable;
       
  1108 
       
  1109 			if (currentFunctionMenu != null) {
       
  1110 				currentFunctionMenu.dispose();
       
  1111 			}
       
  1112 
       
  1113 			currentFunctionMenu = new Menu(currentFunctionTable.getShell(), SWT.POP_UP); 
       
  1114 			
       
  1115 //			new MenuItem(callerMenu, SWT.SEPARATOR);
       
  1116 			
       
  1117 			MenuItem sourceLookupItem = new MenuItem(currentFunctionMenu, SWT.PUSH);
       
  1118 			sourceLookupItem.setText(Messages.getString("CallVisualiser.sourcelookup"));	//$NON-NLS-1$
       
  1119 			sourceLookupItem.addSelectionListener(new SelectionListener() {
       
  1120 
       
  1121 				public void widgetDefaultSelected(SelectionEvent arg0) {
       
  1122 				}
       
  1123 
       
  1124 				public void widgetSelected(SelectionEvent arg0) {
       
  1125 					doSourceLookup(currentFunctionTable);
       
  1126 				}
       
  1127 				
       
  1128 			});
       
  1129 			
       
  1130 			if (currentFunctionTable.getSelectionCount() == 0) {
       
  1131 				sourceLookupItem.setEnabled(false);
       
  1132 			}
       
  1133 
       
  1134 			// add copy, copy all, copy caller/callee info, save all, save caller/callee info
       
  1135 			new MenuItem(currentFunctionMenu, SWT.SEPARATOR);
       
  1136 			getCopyItem(currentFunctionMenu, currentFunctionTable.getSelectionCount() > 0);
       
  1137 			getCopyTableItem(currentFunctionMenu, currentFunctionTable.getItemCount() > 0);
       
  1138 			getCopyFunctionItem(currentFunctionMenu, currentFunctionTable.getSelectionCount() > 0);
       
  1139 			copyAction.setEnabled(currentFunctionTable.getSelectionCount() > 0);
       
  1140 			copyTableAction.setEnabled(currentFunctionTable.getItemCount() > 0);
       
  1141 			functionCopyFunctionAction.setEnabled(currentFunctionTable.getSelectionCount() > 0);
       
  1142 
       
  1143 			new MenuItem(currentFunctionMenu, SWT.SEPARATOR);
       
  1144 			getSaveTableItem(currentFunctionMenu, currentFunctionTable.getItemCount() > 0);
       
  1145 			getSaveFunctionItem(currentFunctionMenu, currentFunctionTable.getSelectionCount() > 0);
       
  1146 			saveTableAction.setEnabled(currentFunctionTable.getItemCount() > 0);
       
  1147 			functionSaveFunctionAction.setEnabled(currentFunctionTable.getSelectionCount() > 0);
       
  1148 			
       
  1149 			// save samples
       
  1150 			int startTime = (int) (PIPageEditor.currentPageEditor().getStartTime() * 1000.0f);
       
  1151 			int endTime   = (int) (PIPageEditor.currentPageEditor().getEndTime()   * 1000.0f);
       
  1152 
       
  1153 			if ((startTime == -1) || (endTime   == -1) || (startTime == endTime))
       
  1154 				getSaveSamplesItem(currentFunctionMenu, false); //$NON-NLS-1$
       
  1155 			else
       
  1156 				getSaveSamplesItem(currentFunctionMenu, true); //$NON-NLS-1$
       
  1157 
       
  1158 			currentFunctionMenu.setLocation(currentFunctionTable.getParent().toDisplay(me.x, me.y));
       
  1159 			currentFunctionMenu.setVisible(true);
       
  1160 			currentFunctionTable.setMenu(currentFunctionMenu);
       
  1161 		}
       
  1162 	}
       
  1163 
       
  1164 	private class CalleeMouseListener implements MouseListener
       
  1165 	{
       
  1166 		public void mouseDoubleClick(org.eclipse.swt.events.MouseEvent me) {}
       
  1167 
       
  1168 		public void mouseDown(org.eclipse.swt.events.MouseEvent me) {}
       
  1169 
       
  1170 		public void mouseUp(org.eclipse.swt.events.MouseEvent me) {
       
  1171 			copyAction.setEnabled(calleeTable.getSelectionCount() > 0);
       
  1172 			copyTableAction.setEnabled(calleeTable.getItemCount() > 0);
       
  1173 
       
  1174 			// only look for button 3 (right click)
       
  1175 			if (me.button != MouseEvent.BUTTON3)
       
  1176 				return;
       
  1177 
       
  1178 			// make the callee table the menu table
       
  1179 			currentMenuTable = calleeTable;
       
  1180 
       
  1181 			if (calleeMenu != null) {
       
  1182 				calleeMenu.dispose();
       
  1183 			}
       
  1184 			
       
  1185 			calleeMenu = new Menu(calleeTable.getShell(), SWT.POP_UP); 
       
  1186 			
       
  1187 			MenuItem showCallInfoItem = new MenuItem(calleeMenu, SWT.PUSH);
       
  1188 			showCallInfoItem.setText(Messages.getString("CallVisualiser.showCallInfo")); //$NON-NLS-1$
       
  1189 			showCallInfoItem.addSelectionListener(new SelectionAdapter() { 
       
  1190 				public void widgetSelected(SelectionEvent se) {
       
  1191 				    // based on the table's selected item, update the tables
       
  1192 					TableItem[] selections = calleeTable.getSelection();
       
  1193 					calleeTable.deselectAll();
       
  1194 					
       
  1195 					if (selections.length != 0)
       
  1196 						chooseNewFunction((CallerCalleeItem)selections[0].getData());
       
  1197 				}
       
  1198 			});
       
  1199 			
       
  1200 			new MenuItem(calleeMenu, SWT.SEPARATOR);
       
  1201 			
       
  1202 			MenuItem sourceLookupItem = new MenuItem(calleeMenu, SWT.PUSH);
       
  1203 			sourceLookupItem.setText(Messages.getString("CallVisualiser.sourcelookup"));	//$NON-NLS-1$
       
  1204 			sourceLookupItem.addSelectionListener(new SelectionListener() {
       
  1205 
       
  1206 				public void widgetDefaultSelected(SelectionEvent arg0) {
       
  1207 				}
       
  1208 
       
  1209 				public void widgetSelected(SelectionEvent arg0) {
       
  1210 					doSourceLookup(calleeTable);
       
  1211 				}
       
  1212 				
       
  1213 			});
       
  1214 			
       
  1215 			if (calleeTable.getSelectionCount() == 0) {
       
  1216 				showCallInfoItem.setEnabled(false);
       
  1217 				sourceLookupItem.setEnabled(false);
       
  1218 			}
       
  1219 
       
  1220 			// add copy, copy all, and save all
       
  1221 			new MenuItem(calleeMenu, SWT.SEPARATOR);
       
  1222 			getCopyItem(calleeMenu, calleeTable.getSelectionCount() > 0);
       
  1223 			getCopyTableItem(calleeMenu, calleeTable.getItemCount() > 0);
       
  1224 			copyAction.setEnabled(calleeTable.getSelectionCount() > 0);
       
  1225 			copyTableAction.setEnabled(calleeTable.getItemCount() > 0);
       
  1226 
       
  1227 			new MenuItem(calleeMenu, SWT.SEPARATOR);
       
  1228 			getSaveTableItem(calleeMenu, calleeTable.getItemCount() > 0);
       
  1229 			saveTableAction.setEnabled(calleeTable.getItemCount() > 0);
       
  1230 			
       
  1231 			// save samples
       
  1232 			int startTime = (int) (PIPageEditor.currentPageEditor().getStartTime() * 1000.0f);
       
  1233 			int endTime   = (int) (PIPageEditor.currentPageEditor().getEndTime()   * 1000.0f);
       
  1234 
       
  1235 			if ((startTime == -1) || (endTime   == -1) || (startTime == endTime))
       
  1236 				getSaveSamplesItem(calleeMenu, false); //$NON-NLS-1$
       
  1237 			else
       
  1238 				getSaveSamplesItem(calleeMenu, true); //$NON-NLS-1$
       
  1239 
       
  1240 			calleeMenu.setLocation(calleeTable.getParent().toDisplay(me.x, me.y));
       
  1241 			calleeMenu.setVisible(true);
       
  1242 			calleeTable.setMenu(calleeMenu);
       
  1243 		}
       
  1244 	}
       
  1245 	
       
  1246 	protected void createDefaultActions(boolean copyFunction)
       
  1247 	{
       
  1248 		copyAction = new Action(Messages.getString("CallVisualiser.0")) { //$NON-NLS-1$
       
  1249 			public void run() {
       
  1250 				action("copy"); //$NON-NLS-1$
       
  1251 			}
       
  1252 		};
       
  1253 		copyAction.setEnabled(false);
       
  1254 
       
  1255 		copyTableAction = new Action(Messages.getString("CallVisualiser.1")) { //$NON-NLS-1$
       
  1256 			public void run() {
       
  1257 				action("copyTable"); //$NON-NLS-1$
       
  1258 			}
       
  1259 		};
       
  1260 		copyTableAction.setEnabled(true);
       
  1261 		copyTableAction.setId("PICopyTable"); //$NON-NLS-1$
       
  1262 		copyTableAction.setText(Messages.getString("CallVisualiser.CopyTable")); //$NON-NLS-1$
       
  1263 
       
  1264 		saveTableAction = new Action(Messages.getString("CallVisualiser.2")) { //$NON-NLS-1$
       
  1265 			public void run() {
       
  1266 				action("saveTable"); //$NON-NLS-1$
       
  1267 			}
       
  1268 		};
       
  1269 		saveTableAction.setEnabled(true);
       
  1270 		saveTableAction.setId("PISaveTable"); //$NON-NLS-1$
       
  1271 		saveTableAction.setText(Messages.getString("CallVisualiser.SaveTable")); //$NON-NLS-1$
       
  1272 
       
  1273 		functionCopyFunctionAction = new Action(Messages.getString("CallVisualiser.3")) { //$NON-NLS-1$
       
  1274 			public void run() {
       
  1275 				action("copyFunction"); //$NON-NLS-1$
       
  1276 			}
       
  1277 		};
       
  1278 		functionCopyFunctionAction.setEnabled(true);
       
  1279 		functionCopyFunctionAction.setId("PICopyFunction"); //$NON-NLS-1$
       
  1280 		functionCopyFunctionAction.setText(Messages.getString("CallVisualiser.CopyDataForFunction")); //$NON-NLS-1$
       
  1281 
       
  1282 		functionSaveFunctionAction = new Action(Messages.getString("CallVisualiser.4")) { //$NON-NLS-1$
       
  1283 			public void run() {
       
  1284 				action("saveFunction"); //$NON-NLS-1$
       
  1285 			}
       
  1286 		};
       
  1287 		functionSaveFunctionAction.setEnabled(true);
       
  1288 		functionSaveFunctionAction.setId("PISaveFunction"); //$NON-NLS-1$
       
  1289 		functionSaveFunctionAction.setText(Messages.getString("CallVisualiser.SaveDataForFunction")); //$NON-NLS-1$
       
  1290 	}
       
  1291 
       
  1292 	private class SharedLabelProvider extends LabelProvider implements ITableLabelProvider {
       
  1293 		
       
  1294 		Table table;
       
  1295 
       
  1296 		public SharedLabelProvider(Table table) {
       
  1297 			super();
       
  1298 			this.table = table;
       
  1299 		}
       
  1300 
       
  1301 		public String getColumnText(Object element, int columnIndex) {
       
  1302 			if (   !(element instanceof GfcFunctionItem)
       
  1303 				&& !(element instanceof CallerCalleeItem))
       
  1304 				return ""; //$NON-NLS-1$
       
  1305 
       
  1306 			int columnId = ((Integer) this.table.getColumn(columnIndex).getData()).intValue();
       
  1307 			
       
  1308 			GfcFunctionItem item = null;
       
  1309 			
       
  1310 			if (element instanceof GfcFunctionItem)
       
  1311 				item = (GfcFunctionItem)element;
       
  1312 			else
       
  1313 				item = ((CallerCalleeItem)element).item;
       
  1314 
       
  1315 			switch (columnId)
       
  1316 			{
       
  1317 				case COLUMN_ID_CALLEE_PERCENT:
       
  1318 				case COLUMN_ID_CALLER_PERCENT:
       
  1319 				{
       
  1320 					double percent;
       
  1321 					if (element instanceof CallerCalleeItem)
       
  1322 						percent = ((CallerCalleeItem)element).percent;
       
  1323 					else
       
  1324 						percent = 0.0;
       
  1325 						
       
  1326 					// Percent load string
       
  1327 					return (new DecimalFormat(Messages.getString("CallVisualiser.shortDecimalFormat"))).format(percent); //$NON-NLS-1$
       
  1328 				}
       
  1329 				case COLUMN_ID_FUNCTION:
       
  1330 				{
       
  1331 					// Function
       
  1332 					return item.name;
       
  1333 				}
       
  1334 				case COLUMN_ID_START_ADDR:
       
  1335 				{
       
  1336 					// Function start
       
  1337 					return Long.toHexString(item.address);
       
  1338 				}
       
  1339 				case COLUMN_ID_IN_BINARY:
       
  1340 				{
       
  1341 					// Binary
       
  1342 					String binary = item.dllName;
       
  1343 					int index = binary.lastIndexOf('\\');
       
  1344 					if (index == -1)
       
  1345 						return binary;
       
  1346 					else
       
  1347 						return binary.substring(index + 1);
       
  1348 				}
       
  1349 				case COLUMN_ID_IN_BINARY_PATH:
       
  1350 				{
       
  1351 					// Path
       
  1352 					String binary = item.dllName;
       
  1353 					int index = binary.lastIndexOf('\\');
       
  1354 					if (index == -1)
       
  1355 						return ""; //$NON-NLS-1$
       
  1356 					else
       
  1357 						return binary.substring(0, index);
       
  1358 				}
       
  1359 				case COLUMN_ID_IS_CALLED:
       
  1360 				{
       
  1361 					// Percent load string
       
  1362 					return (new DecimalFormat(Messages.getString("CallVisualiser.decimalFormat"))).format(myTrace.getAbsoluteTraditionalPercentageFor(item)); //$NON-NLS-1$
       
  1363 				}
       
  1364 				case COLUMN_ID_IS_CALLER:
       
  1365 				{
       
  1366 					// Percent load string
       
  1367 					return (new DecimalFormat(Messages.getString("CallVisualiser.decimalFormat"))).format(myTrace.getAbsoluteCallerPercentageFor(item)); //$NON-NLS-1$
       
  1368 				}
       
  1369 				case COLUMN_ID_RECURSIVE_CALL:
       
  1370 				{
       
  1371 					// Percent load string
       
  1372 					return (new DecimalFormat(Messages.getString("CallVisualiser.decimalFormat"))).format(myTrace.getRecursiveCallerPrecentageFor(item)); //$NON-NLS-1$
       
  1373 				}
       
  1374 				case COLUMN_ID_IS_CALLED_COUNT:
       
  1375 				{
       
  1376 					// Sample count
       
  1377 					int samples;
       
  1378 					if (element instanceof CallerCalleeItem)
       
  1379 						samples = ((CallerCalleeItem)element).samples;
       
  1380 					else
       
  1381 						samples = item.isCalledCount();
       
  1382 					return String.valueOf(samples);
       
  1383 				}
       
  1384 				case COLUMN_ID_IS_CALLER_COUNT:
       
  1385 				{
       
  1386 					// Sample count
       
  1387 					int samples;
       
  1388 					if (element instanceof CallerCalleeItem)
       
  1389 						samples = ((CallerCalleeItem)element).samples;
       
  1390 					else
       
  1391 						samples = item.isCallerCount();
       
  1392 					return String.valueOf(samples);
       
  1393 				}
       
  1394 				default:
       
  1395 				{
       
  1396 					break;
       
  1397 				}
       
  1398 			}
       
  1399 			// should never get here
       
  1400 			return ""; //$NON-NLS-1$
       
  1401 		}
       
  1402 
       
  1403 		public Image getColumnImage(Object element, int columnIndex) {
       
  1404 			return null;
       
  1405 		}
       
  1406 	}
       
  1407 
       
  1408 	public void selectFunction(String functionName)
       
  1409 	{
       
  1410 	}
       
  1411   
       
  1412 	public void setStartAndEnd(int start, int end)
       
  1413 	{
       
  1414 		if (this.myTrace == null)
       
  1415 			return;
       
  1416 		
       
  1417 	    this.myTrace.parseEntries(start, end);
       
  1418 	    this.functionArray = myTrace.getEntriesSorted(GfcTrace.SORT_BY_TOTAL_LOAD);
       
  1419 	    this.currentFunctionTableViewer.setInput(this.functionArray);
       
  1420 		
       
  1421 	    updateCallerCalleeTables(null);
       
  1422 	    
       
  1423 	    Table table = this.currentFunctionTableViewer.getTable();
       
  1424 	    
       
  1425 	    if (table.getItemCount() == 0)
       
  1426 	    	return;
       
  1427 	    
       
  1428 	    if (table.getSortColumn() == null) {
       
  1429 	    	table.setSortColumn(currentFunctionDefaultColumn);
       
  1430 	    	table.setSortDirection(SWT.UP);
       
  1431 	    } else {
       
  1432 	    	// use the user's preferred sort column, if any
       
  1433 	    	boolean sortAscending = !((SharedSorter) currentFunctionTableViewer.getSorter()).getSortAscending();
       
  1434 			((SharedSorter) currentFunctionTableViewer.getSorter()).setSortAscending(sortAscending);
       
  1435 	    }
       
  1436 	    
       
  1437 	    sortAndRefresh(this.currentFunctionTableViewer, table.getSortColumn());
       
  1438 	}
       
  1439 
       
  1440 	private static class CallerCalleeItem {
       
  1441 	    GfcFunctionItem item;
       
  1442 	    double percent;
       
  1443 	    int samples;
       
  1444 	}
       
  1445 	
       
  1446 	public void setCallerListToFunctionsThatCallThisFunction(GfcFunctionItem function)
       
  1447 	{
       
  1448 		if (function == null) {
       
  1449 			this.callerList = null;
       
  1450 			return;
       
  1451 		}
       
  1452 
       
  1453 		GfcFunctionItem[] list = function.getCallerList();
       
  1454 	    Double[] perc = function.getCallerPercentages();
       
  1455 	
       
  1456 	    this.callerList = new CallerCalleeItem[list.length];
       
  1457 	    
       
  1458 	    for (int i = 0; i < list.length; i++)
       
  1459 	    {
       
  1460 	    	this.callerList[i] = new CallerCalleeItem();
       
  1461 	    	this.callerList[i].item    = list[i];
       
  1462 	    	this.callerList[i].percent = perc[i];
       
  1463 	    	this.callerList[i].samples = (int) (perc[i] * function.isCalledCount() + 0.5) / 100;
       
  1464 	    }
       
  1465 	}
       
  1466 
       
  1467 	public void setCalleeListToFunctionsThisFunctionCalls(GfcFunctionItem function)
       
  1468 	{
       
  1469 		if (function == null) {
       
  1470 			this.calleeList = null;
       
  1471 			return;
       
  1472 		}
       
  1473 
       
  1474 	    GfcFunctionItem[] list = function.getCalleeList();
       
  1475 	    Double[] perc = function.getCalleePercentages();
       
  1476 	
       
  1477 	    this.calleeList = new CallerCalleeItem[list.length];
       
  1478 	    
       
  1479 	    for (int i = 0; i < list.length; i++)
       
  1480 	    {
       
  1481 	    	this.calleeList[i] = new CallerCalleeItem();
       
  1482 	    	this.calleeList[i].item    = list[i];
       
  1483 	    	this.calleeList[i].percent = perc[i];
       
  1484 	    	this.calleeList[i].samples = (int) (perc[i] * function.isCallerCount() + 0.5) / 100;
       
  1485 	    }
       
  1486 	}
       
  1487 
       
  1488 	public void action(String actionString) {
       
  1489 		if (actionString.equals("copy")) //$NON-NLS-1$
       
  1490 	    {
       
  1491 	    	actionCopyOrSave(true, currentMenuTable, CHECKBOX_NONE, false, "\t", "\n"); //$NON-NLS-1$ //$NON-NLS-2$
       
  1492 	        return;
       
  1493 	    }
       
  1494 	    else if (actionString.equals("copyTable")) //$NON-NLS-1$
       
  1495 	    {
       
  1496 	    	actionCopyOrSave(true, currentMenuTable, CHECKBOX_NONE, true, "\t", "\n"); //$NON-NLS-1$ //$NON-NLS-2$
       
  1497 	        return;
       
  1498 	    }
       
  1499 	    else if (actionString.equals("copyFunction")) //$NON-NLS-1$
       
  1500 	    {
       
  1501 	    	actionCopyOrSaveFunction(true, "\t"); //$NON-NLS-1$
       
  1502 	        return;
       
  1503 	    }
       
  1504 	    else if (actionString.equals("saveTable")) //$NON-NLS-1$
       
  1505 	    {
       
  1506 	    	actionCopyOrSave(false, currentMenuTable, CHECKBOX_NONE, true, ",", "\n"); //$NON-NLS-1$ //$NON-NLS-2$
       
  1507 	        return;
       
  1508 	    }
       
  1509 	    else if (actionString.equals("saveFunction")) //$NON-NLS-1$
       
  1510 	    {
       
  1511 	    	actionCopyOrSaveFunction(false, ","); //$NON-NLS-1$
       
  1512 	        return;
       
  1513 	    }
       
  1514 	    else if (actionString.equals("saveSamples")) //$NON-NLS-1$
       
  1515 	    {
       
  1516 	    	SaveSampleString saveSampleString = new SaveSampleString();
       
  1517 	    	actionSaveSamples(saveSampleString); //$NON-NLS-1$
       
  1518 	        return;
       
  1519 	    }
       
  1520 	    else if (actionString.equals("saveTableTest")) //$NON-NLS-1$
       
  1521 	    {
       
  1522 			// copy save file contents to the clipboard for easy viewing
       
  1523 	        Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
       
  1524 			SaveTableString getString = new SaveTableString(currentMenuTable, CHECKBOX_NONE, ",", "\n"); //$NON-NLS-1$ //$NON-NLS-2$
       
  1525 	        String copyString = getString.getData();
       
  1526 			StringSelection contents = new StringSelection(copyString);
       
  1527 	        cb.setContents(contents, contents);
       
  1528 	        return;
       
  1529 	    }
       
  1530 	    else if (actionString.equals("saveFunctionTest")) //$NON-NLS-1$
       
  1531 	    {
       
  1532 			// copy save file contents to the clipboard for easy viewing
       
  1533 	        Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
       
  1534 	        SaveFunctionString getString = new SaveFunctionString(","); //$NON-NLS-1$
       
  1535 	        String copyString = getString.getData();
       
  1536 			StringSelection contents = new StringSelection(copyString);
       
  1537 	        cb.setContents(contents, contents);
       
  1538 	        return;
       
  1539 	    }
       
  1540 	}
       
  1541 	
       
  1542 	/*
       
  1543 	 * TableViewer sorter for the called-by and called function tableviewers
       
  1544 	 */
       
  1545 	private class SharedSorter extends ViewerSorter {
       
  1546 		// sort direction
       
  1547 		private boolean sortAscending;
       
  1548 		
       
  1549 		// last column sorted
       
  1550 		private int column = -1;
       
  1551 		
       
  1552 		/* 
       
  1553 		 * decide on which column to sort by, and the sort ordering
       
  1554 		 */
       
  1555 		public void doSort(int column) {
       
  1556 			// ignore the column passed in and use the id set by the column selection handler
       
  1557 			if (column == this.column) {
       
  1558 				// sort in other order
       
  1559 				sortAscending = !sortAscending;
       
  1560 			} else {
       
  1561 				switch (column) {
       
  1562 					case COLUMN_ID_FUNCTION:
       
  1563 					case COLUMN_ID_START_ADDR:
       
  1564 					case COLUMN_ID_IN_BINARY:
       
  1565 					case COLUMN_ID_IN_BINARY_PATH:
       
  1566 					{
       
  1567 		            	// sort in ascending order
       
  1568 		            	sortAscending = true;
       
  1569 		                break;
       
  1570 					}
       
  1571 					case COLUMN_ID_IS_CALLED:
       
  1572 					case COLUMN_ID_IS_CALLER:
       
  1573 					case COLUMN_ID_RECURSIVE_CALL:
       
  1574 					case COLUMN_ID_CALLER_PERCENT:
       
  1575 					case COLUMN_ID_CALLEE_PERCENT:
       
  1576 					case COLUMN_ID_IS_CALLED_COUNT:
       
  1577 					case COLUMN_ID_IS_CALLER_COUNT:
       
  1578 					{
       
  1579 		            	// sort in descending order
       
  1580 		            	sortAscending = false;
       
  1581 		                break;
       
  1582 					}
       
  1583 					default:
       
  1584 					{
       
  1585 						// ignore the column
       
  1586 						return;
       
  1587 					}
       
  1588 				}
       
  1589 				this.column = column;
       
  1590 			}
       
  1591 		}
       
  1592 		
       
  1593 		/*
       
  1594 		 * compare two items from a table column
       
  1595 		 */
       
  1596 		public int compare(Viewer viewer, Object e1, Object e2) {
       
  1597 			int comparison = 0;
       
  1598 			
       
  1599 			GfcFunctionItem item1 = null;
       
  1600 			GfcFunctionItem item2 = null;
       
  1601 			CallerCalleeItem ccItem1 = null;
       
  1602 			CallerCalleeItem ccItem2 = null;
       
  1603 			
       
  1604 			if (e1 instanceof GfcFunctionItem) {
       
  1605 				item1 = (GfcFunctionItem) e1;
       
  1606 				item2 = (GfcFunctionItem) e2;
       
  1607 			} else {
       
  1608 				ccItem1 = (CallerCalleeItem)e1;
       
  1609 				ccItem2 = (CallerCalleeItem)e2;
       
  1610 				item1 =   ccItem1.item;
       
  1611 				item2 =   ccItem2.item;
       
  1612 			}
       
  1613 
       
  1614 			switch (column) {
       
  1615 				case COLUMN_ID_CALLER_PERCENT:
       
  1616 				case COLUMN_ID_CALLEE_PERCENT:
       
  1617 				{
       
  1618 					double percent1;
       
  1619 					double percent2;
       
  1620 					if (e1 instanceof GfcFunctionItem) {
       
  1621 						percent1 = 0.0;
       
  1622 						percent2 = 0.0;
       
  1623 					} else {
       
  1624 						percent1 = ccItem1.percent;
       
  1625 						percent2 = ccItem2.percent;
       
  1626 					}
       
  1627 					comparison = percent1 > percent2 ? 1 : -1;
       
  1628 					break;
       
  1629 				}
       
  1630 				case COLUMN_ID_FUNCTION:
       
  1631 				{
       
  1632 					comparison = this.getComparator().compare(item1.name, item2.name);
       
  1633 					break;
       
  1634 				}
       
  1635 				case COLUMN_ID_START_ADDR:
       
  1636 				{
       
  1637 					comparison = (item1.address > item2.address) ? 1 : -1; 
       
  1638 					break;
       
  1639 				}
       
  1640 				case COLUMN_ID_IN_BINARY:
       
  1641 				{
       
  1642 					int index;
       
  1643 					String name1 = item1.dllName;
       
  1644 					index = name1.lastIndexOf('\\');
       
  1645 					if (index != -1)
       
  1646 						name1 = name1.substring(index);
       
  1647 
       
  1648 					String name2 = item2.dllName;
       
  1649 					index = name2.lastIndexOf('\\');
       
  1650 					if (index != -1)
       
  1651 						name2 = name2.substring(index);
       
  1652 
       
  1653 					comparison = this.getComparator().compare(name1, name2);
       
  1654 					break;
       
  1655 				}
       
  1656 				case COLUMN_ID_IN_BINARY_PATH:
       
  1657 				{
       
  1658 					int index;
       
  1659 					String name1 = item1.dllName;
       
  1660 					index = name1.lastIndexOf('\\');
       
  1661 					if (index == -1)
       
  1662 						name1 = ""; //$NON-NLS-1$
       
  1663 					else
       
  1664 						name1 = name1.substring(0, index);
       
  1665 
       
  1666 					String name2 = item2.dllName;
       
  1667 					index = name2.lastIndexOf('\\');
       
  1668 					if (index == -1)
       
  1669 						name2 = ""; //$NON-NLS-1$
       
  1670 					else
       
  1671 						name2 = name2.substring(0, index);
       
  1672 
       
  1673 					comparison = this.getComparator().compare(name1, name2);
       
  1674 					break;
       
  1675 				}
       
  1676 				case COLUMN_ID_IS_CALLED:
       
  1677 				{
       
  1678 					// actual sample count used as a proxy for the percentage
       
  1679 					comparison = item1.isCalledCount() - item2.isCalledCount();
       
  1680 					break;
       
  1681 				}
       
  1682 				case COLUMN_ID_IS_CALLER:
       
  1683 				{
       
  1684 					// actual sample count used as a proxy for the percentage
       
  1685 					comparison = item1.isCallerCount() - item2.isCallerCount();
       
  1686 					break;
       
  1687 				}
       
  1688 				case COLUMN_ID_RECURSIVE_CALL:
       
  1689 				{
       
  1690 					comparison = myTrace.getRecursiveCallerPrecentageFor(item1) >
       
  1691 								 myTrace.getRecursiveCallerPrecentageFor(item2) ? 1 : -1;
       
  1692 					break;
       
  1693 				}
       
  1694 				case COLUMN_ID_IS_CALLED_COUNT:
       
  1695 				{
       
  1696 					if (e1 instanceof GfcFunctionItem) {
       
  1697 						comparison = item1.isCalledCount() - item2.isCalledCount();
       
  1698 					} else {
       
  1699 						comparison = ccItem1.samples - ccItem2.samples;
       
  1700 					}
       
  1701 					break;
       
  1702 				}
       
  1703 				case COLUMN_ID_IS_CALLER_COUNT:
       
  1704 				{
       
  1705 					if (e1 instanceof GfcFunctionItem) {
       
  1706 						comparison = item1.isCallerCount() - item2.isCallerCount();
       
  1707 					} else {
       
  1708 						comparison = ccItem1.samples - ccItem2.samples;
       
  1709 					}
       
  1710 					break;
       
  1711 				}
       
  1712 				default:
       
  1713 				{
       
  1714 					break;
       
  1715 				}
       
  1716 			}
       
  1717 
       
  1718 			// for descending order, reverse the sense of the compare
       
  1719 			if (!sortAscending)
       
  1720 				comparison = -comparison;
       
  1721 			return comparison;
       
  1722 		}
       
  1723 		
       
  1724 		public boolean getSortAscending() {
       
  1725 			return sortAscending;
       
  1726 		}
       
  1727 		
       
  1728 		public void setSortAscending(boolean sortAscending) {
       
  1729 			this.sortAscending = sortAscending;
       
  1730 		}
       
  1731 		
       
  1732 		public int getColumnID() {
       
  1733 			return column;
       
  1734 		}
       
  1735 	}
       
  1736 	
       
  1737 	public void sortAndRefresh(TableViewer tableViewer, TableColumn tableColumn)
       
  1738 	{
       
  1739 		Table table = tableViewer.getTable();
       
  1740     	int columnID = ((Integer) tableColumn.getData()).intValue();
       
  1741     	
       
  1742     	if (table.getItemCount() == 0)
       
  1743     		return;
       
  1744 		
       
  1745 		// sort by selected columnID
       
  1746     	((SharedSorter) tableViewer.getSorter()).doSort(columnID);
       
  1747 		table.setSortColumn(tableColumn);
       
  1748 		table.setSortDirection(((SharedSorter) tableViewer.getSorter()).getSortAscending() ? SWT.UP : SWT.DOWN);
       
  1749 		tableViewer.refresh();
       
  1750 	}
       
  1751 
       
  1752 	private class CalledByColumnSelectionHandler extends SelectionAdapter
       
  1753 	{
       
  1754 		public void widgetSelected(SelectionEvent e)
       
  1755         {
       
  1756         	if (!(e.widget instanceof TableColumn))
       
  1757         		return;
       
  1758         	
       
  1759         	sortAndRefresh(callerTableViewer, (TableColumn) e.widget);
       
  1760        }
       
  1761 	}
       
  1762 
       
  1763 	private class CalledColumnSelectionHandler extends SelectionAdapter
       
  1764 	{
       
  1765 		public void widgetSelected(SelectionEvent e)
       
  1766         {
       
  1767         	if (!(e.widget instanceof TableColumn))
       
  1768         		return;
       
  1769 
       
  1770         	sortAndRefresh(calleeTableViewer, (TableColumn) e.widget);
       
  1771         }
       
  1772 	}
       
  1773 
       
  1774 	private class CheckboxColumnSelectionHandler extends SelectionAdapter
       
  1775 	{
       
  1776 		public void widgetSelected(SelectionEvent e)
       
  1777         {
       
  1778         	if (!(e.widget instanceof TableColumn))
       
  1779         		return;
       
  1780 
       
  1781         	sortAndRefresh(currentFunctionTableViewer, (TableColumn) e.widget);
       
  1782         }
       
  1783 	}
       
  1784 	
       
  1785 	public PIPageEditor getPageEditor()
       
  1786 	{
       
  1787 		return this.pageEditor;
       
  1788 	}
       
  1789 	
       
  1790 	public int getPageIndex()
       
  1791 	{
       
  1792 		return this.pageIndex;
       
  1793 	}
       
  1794 	
       
  1795 	private MenuItem getCopyFunctionItem(Menu menu, boolean enabled) {
       
  1796 	    MenuItem copyFunctionItem = new MenuItem(menu, SWT.PUSH);
       
  1797 	    
       
  1798 		copyFunctionItem.setText(Messages.getString("CallVisualiser.CopyDataForFunction")); //$NON-NLS-1$
       
  1799 		copyFunctionItem.setEnabled(enabled);
       
  1800 		
       
  1801 		if (enabled) {
       
  1802 			copyFunctionItem.addSelectionListener(new SelectionAdapter() { 
       
  1803 				public void widgetSelected(SelectionEvent e) {
       
  1804 				    action("copyFunction"); //$NON-NLS-1$
       
  1805 				}
       
  1806 			});
       
  1807 		}
       
  1808 		
       
  1809 		return copyFunctionItem;
       
  1810 	}
       
  1811 	
       
  1812 	private MenuItem getSaveFunctionItem(Menu menu, boolean enabled) {
       
  1813 	    MenuItem saveFunctionItem = new MenuItem(menu, SWT.PUSH);
       
  1814 	    
       
  1815 		saveFunctionItem.setText(Messages.getString("CallVisualiser.SaveDataForFunction")); //$NON-NLS-1$
       
  1816 		saveFunctionItem.setEnabled(enabled);
       
  1817 		
       
  1818 		if (enabled) {
       
  1819 			saveFunctionItem.addSelectionListener(new SelectionAdapter() { 
       
  1820 				public void widgetSelected(SelectionEvent e) {
       
  1821 				    action("saveFunction"); //$NON-NLS-1$
       
  1822 				}
       
  1823 			});
       
  1824 		}
       
  1825 		
       
  1826 		return saveFunctionItem;
       
  1827 	}
       
  1828 
       
  1829 	private void doSourceLookup(Table mytable) {
       
  1830 		// source look up for selected items
       
  1831 		if ((mytable.getItemCount() == 0) || (mytable.getSelectionCount() == 0))
       
  1832 			return;
       
  1833 
       
  1834 		TableItem selectedItem = mytable.getSelection()[0];
       
  1835 		Object selectedData = selectedItem.getData();
       
  1836 		String functionName = null;
       
  1837 		String binaryName = null;
       
  1838 		if (selectedData instanceof GfcFunctionItem) {
       
  1839 			GfcFunctionItem functionItem = (GfcFunctionItem) selectedData;
       
  1840 			functionName = functionItem.name;
       
  1841 			binaryName = functionItem.dllName;
       
  1842 		} else if (selectedData instanceof CallerCalleeItem) {
       
  1843 			CallerCalleeItem callerCalleeItem = (CallerCalleeItem) selectedData;
       
  1844 			functionName = callerCalleeItem.item.name;
       
  1845 			binaryName = callerCalleeItem.item.dllName;
       
  1846 		}
       
  1847 		if (functionName != null && binaryName != null)
       
  1848 		{
       
  1849 			SourceLookup.getInstance().lookupAndopenEditorWithHighlight(functionName , binaryName);
       
  1850 		}
       
  1851 
       
  1852 	}
       
  1853 	
       
  1854 	// class to pass the function caller/callee data to the save wizard
       
  1855 	private class SaveFunctionString implements ISaveTable {
       
  1856 		private String separator;
       
  1857 		
       
  1858 		public SaveFunctionString(String separator) {
       
  1859 			this.separator = separator;
       
  1860 		}
       
  1861 
       
  1862 		public String getData() {
       
  1863 			return copyFunction(separator);
       
  1864 		}
       
  1865 	}
       
  1866 	
       
  1867     private void actionCopyOrSaveFunction(boolean doCopy, String separator)
       
  1868     {
       
  1869     	// one function must be selected
       
  1870     	if (currentFunctionTable.getSelectionCount() != 1)
       
  1871     		return;
       
  1872  
       
  1873 		// copy one function's caller and callee data to the clipboard or save to a file
       
  1874 		if (doCopy) {
       
  1875 			// change the clipboard contents
       
  1876 	        Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
       
  1877 			String copyString = copyFunction(separator);
       
  1878 			StringSelection contents = new StringSelection(copyString);
       
  1879 	        cb.setContents(contents, contents);
       
  1880 	    } else {
       
  1881 			SaveFunctionString getString = new SaveFunctionString(separator);
       
  1882 			WizardDialog dialog;
       
  1883 			Wizard w = new SaveTableWizard(getString);
       
  1884 			dialog = new WizardDialog(PlatformUI.getWorkbench().getDisplay().getActiveShell(), w);
       
  1885 	    	dialog.open();
       
  1886 	    }
       
  1887     }
       
  1888 
       
  1889     private String copyFunction(String separator)
       
  1890 	{	
       
  1891     	// one function must be selected
       
  1892     	if (currentFunctionTable.getSelectionCount() != 1)
       
  1893 			return ""; //$NON-NLS-1$
       
  1894 		
       
  1895 		String copyString = ""; //$NON-NLS-1$
       
  1896 
       
  1897 		// create the multiple table heading line (e.g., "Selected Function     Callers")
       
  1898 		// space them out based on how many columns are in their table
       
  1899 		if (currentFunctionTable.getData() instanceof String) {
       
  1900 			copyString += (String) (currentFunctionTable.getData());
       
  1901 		}
       
  1902 		for (int j = 0; j < currentFunctionTable.getColumnCount(); j++) {
       
  1903 			copyString += separator;
       
  1904 		}
       
  1905 
       
  1906 		if (callerTable.getData() instanceof String) {
       
  1907 			copyString += (String) (callerTable.getData());
       
  1908 		}
       
  1909 		for (int j = 0; j < callerTable.getColumnCount(); j++) {
       
  1910 			copyString += separator;
       
  1911 		}
       
  1912 
       
  1913 		if (calleeTable.getData() instanceof String) {
       
  1914 			copyString += (String) (calleeTable.getData());
       
  1915 		}
       
  1916 		for (int j = 0; j < calleeTable.getColumnCount(); j++) {
       
  1917 			copyString += separator;
       
  1918 		}
       
  1919 
       
  1920 		copyString += "\n"; //$NON-NLS-1$
       
  1921 		
       
  1922 		// create the multiple table column headings
       
  1923 		copyString += copyHeading(currentFunctionTable, CHECKBOX_NONE, separator, separator); //$NON-NLS-1$
       
  1924 		copyString += copyHeading(callerTable, CHECKBOX_NONE, separator, separator); //$NON-NLS-1$
       
  1925 		copyString += copyHeading(calleeTable, CHECKBOX_NONE, separator, "\n"); //$NON-NLS-1$
       
  1926 		
       
  1927 		// determine the row, column count, and column ordering in each table
       
  1928 		// NOTE: the first table in the copy will contain the function, and it only its
       
  1929 		// one selected line will be shown
       
  1930 		int rowCount0      = 1;
       
  1931 		int columnCount0   = currentFunctionTable.getColumnCount();
       
  1932 		int[] columnOrder0 = currentFunctionTable.getColumnOrder();
       
  1933 		boolean[] isHex0   = (boolean[]) currentFunctionTable.getData("isHex"); //$NON-NLS-1$
       
  1934 		String emptyRow0 = ""; //$NON-NLS-1$
       
  1935 
       
  1936 		int rowCount1      = callerTable.getItemCount();
       
  1937 		int columnCount1   = callerTable.getColumnCount();
       
  1938 		int[] columnOrder1 = callerTable.getColumnOrder();
       
  1939 		boolean[] isHex1   = (boolean[]) callerTable.getData("isHex"); //$NON-NLS-1$
       
  1940 		String emptyRow1 = ""; //$NON-NLS-1$
       
  1941 
       
  1942 		int rowCount2      = calleeTable.getItemCount();
       
  1943 		int columnCount2   = calleeTable.getColumnCount();
       
  1944 		int[] columnOrder2 = calleeTable.getColumnOrder();
       
  1945 		boolean[] isHex2   = (boolean[]) calleeTable.getData("isHex"); //$NON-NLS-1$
       
  1946 		String emptyRow2 = ""; //$NON-NLS-1$
       
  1947 
       
  1948 		// determine the number of multiple table rows (max of any table's rows) 
       
  1949 		int rowCount = rowCount0 >= rowCount1 ? rowCount0 : rowCount1;
       
  1950 		rowCount = rowCount2 > rowCount ? rowCount2 : rowCount;
       
  1951 		
       
  1952 		// generate empty row strings, to speed things up
       
  1953 		if (rowCount0 < rowCount) {
       
  1954 			for (int j = 0; j < columnCount0 - 1; j++) {
       
  1955 				emptyRow0 += separator;
       
  1956 			}
       
  1957 		}
       
  1958 
       
  1959 		if (rowCount1 < rowCount) {
       
  1960 			for (int j = 0; j < columnCount1; j++) {
       
  1961 				emptyRow1 += separator;
       
  1962 			}
       
  1963 		}
       
  1964 
       
  1965 		if (rowCount2 < rowCount) {
       
  1966 			for (int j = 0; j < columnCount2; j++) {
       
  1967 				emptyRow2 += separator;
       
  1968 			}
       
  1969 		}
       
  1970 
       
  1971 		// generate the rows
       
  1972 		for (int i = 0; i < rowCount; i++) {
       
  1973 			if (i < 1) {
       
  1974 				copyString += copyRow(isHex0, currentFunctionTable.getItem(currentFunctionTable.getSelectionIndex()),
       
  1975 										CHECKBOX_NONE, columnCount0, columnOrder0, separator);
       
  1976 			} else {
       
  1977 				copyString += emptyRow0;
       
  1978 			}
       
  1979 			
       
  1980 			if (i < rowCount1) {
       
  1981 				copyString += separator + copyRow(isHex1, callerTable.getItem(i), CHECKBOX_NONE, columnCount1, columnOrder1, separator);
       
  1982 			} else {
       
  1983 				// NOTE: if this is the last table, or the 3rd table has nothing but empty
       
  1984 				// rows left, we may not need to fill in these fields
       
  1985 				copyString += emptyRow1;
       
  1986 			}
       
  1987 			
       
  1988 			if (i < rowCount2) {
       
  1989 				copyString += separator + copyRow(isHex2, calleeTable.getItem(i), CHECKBOX_NONE, columnCount2, columnOrder2, separator);
       
  1990 			} else {
       
  1991 				// NOTE: we may not need to fill in the empty fields of the last table
       
  1992 				copyString += emptyRow2;
       
  1993 			}
       
  1994 			
       
  1995 			copyString += "\n"; //$NON-NLS-1$
       
  1996 		}
       
  1997 		
       
  1998 		return copyString;
       
  1999 	}
       
  2000 	
       
  2001     // added to give JUnit tests access
       
  2002 	public TableViewer getCallerViewer() {
       
  2003 		return this.callerTableViewer;
       
  2004 	}
       
  2005 	
       
  2006     // added to give JUnit tests access
       
  2007 	public TableViewer getCurrentFunctionViewer() {
       
  2008 		return this.currentFunctionTableViewer;
       
  2009 	}
       
  2010 	
       
  2011     // added to give JUnit tests access
       
  2012 	public TableViewer getCalleeViewer() {
       
  2013 		return this.calleeTableViewer;
       
  2014 	}
       
  2015 	
       
  2016     // added to give JUnit tests access
       
  2017 	public void setCurrentMenuTable(Table currentMenuTable) {
       
  2018 		this.currentMenuTable = currentMenuTable;
       
  2019 	}
       
  2020 }