sysperfana/perfinvestigator/com.nokia.carbide.cpp.pi.address/src/com/nokia/carbide/cpp/pi/address/GenericAddrTable.java
changeset 2 b9ab3b238396
child 5 844b047e260d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sysperfana/perfinvestigator/com.nokia.carbide.cpp.pi.address/src/com/nokia/carbide/cpp/pi/address/GenericAddrTable.java	Thu Feb 11 15:32:31 2010 +0200
@@ -0,0 +1,1156 @@
+/*
+ * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). 
+ * All rights reserved.
+ * This component and the accompanying materials are made available
+ * under the terms of the License "Eclipse Public License v1.0"
+ * which accompanies this distribution, and is available
+ * at the URL "http://www.eclipse.org/legal/epl-v10.html".
+ *
+ * Initial Contributors:
+ * Nokia Corporation - initial contribution.
+ *
+ * Contributors:
+ *
+ * Description: 
+ *
+ */
+
+package com.nokia.carbide.cpp.pi.address;
+
+import java.awt.Toolkit;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.StringSelection;
+import java.awt.event.MouseEvent;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.ActionContributionItem;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IContributionManager;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.SubMenuManager;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Decorations;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.ActionFactory;
+import org.eclipse.ui.ide.IIDEActionConstants;
+
+import com.nokia.carbide.cpp.internal.pi.interfaces.ISaveSamples;
+import com.nokia.carbide.cpp.internal.pi.interfaces.ISaveTable;
+import com.nokia.carbide.cpp.internal.pi.model.ProfiledBinary;
+import com.nokia.carbide.cpp.internal.pi.model.ProfiledFunction;
+import com.nokia.carbide.cpp.internal.pi.model.ProfiledGeneric;
+import com.nokia.carbide.cpp.internal.pi.model.ProfiledThread;
+import com.nokia.carbide.cpp.internal.pi.save.SaveTableWizard;
+import com.nokia.carbide.cpp.internal.pi.visual.Defines;
+import com.nokia.carbide.cpp.internal.pi.visual.GenericTable;
+import com.nokia.carbide.cpp.pi.editors.PIPageEditor;
+
+
+public abstract class GenericAddrTable extends GenericTable
+{
+	protected GppTraceGraph myGraph;
+	protected Composite     parent;
+
+	// sorting column and order
+	protected int     sortColumn = COLUMN_ID_SAMPLE_COUNT;
+	protected boolean sortAscending;
+
+	protected GppTableSorter sorter;
+	protected boolean sorting = false;
+
+	abstract protected Menu getTableMenu(Decorations parent, int graphIndex, int drawMode);
+	
+	protected boolean isDrilldown = false;
+    
+	// menu items
+	protected Action selectAllAction;
+	protected Action copyTableAction;
+	protected Action copyAction;
+	protected Action copyDrilldownAction;
+	protected Action saveTableAction;
+	protected Action saveDrilldownAction;
+	
+	protected static int SAMPLES_AT_ONE_TIME = 1000;
+
+	// class to pass sample data to the save wizard
+    public class SaveSampleString implements ISaveSamples {
+     	int graphIndex;
+    	int drawMode;
+    	int startIndex = 0;
+    	
+    	public SaveSampleString(int graphIndex, int drawMode) {
+    		this.graphIndex = graphIndex;
+    		this.drawMode   = drawMode;
+		}
+
+    	public String getData() {
+    		return getData(SAMPLES_AT_ONE_TIME);
+		}
+
+		public String getData(int size) {
+			String returnString = getSampleString(graphIndex, drawMode, this.startIndex, this.startIndex + size);
+    		if (returnString == null)
+    			this.startIndex = 0;
+    		else
+    			this.startIndex += size;
+			return returnString;
+		}
+		
+		public int getIndex() {
+			return this.startIndex;
+		}
+
+		public void clear() {
+			this.startIndex = 0;
+		}
+    }
+	
+	protected MenuItem getSaveSamplesItem(Menu menu, String sampleType, boolean enabled) {
+	    MenuItem saveSamplesItem = new MenuItem(menu, SWT.PUSH);
+
+		saveSamplesItem.setText(Messages.getString("GenericAddrTable.saveSamples1") + sampleType + Messages.getString("GenericAddrTable.saveSamples2"));   //$NON-NLS-1$ //$NON-NLS-2$
+		saveSamplesItem.setEnabled(enabled);
+		
+		if (enabled) {
+			saveSamplesItem.addSelectionListener(new SelectionAdapter() { 
+				public void widgetSelected(SelectionEvent e) {
+					action("saveSamples"); //$NON-NLS-1$
+				}
+			});
+		}
+	
+		return saveSamplesItem;
+	}
+
+	public GppTraceGraph getGraph() {
+		return myGraph;
+	}
+
+	protected class TableMouseListener implements MouseListener
+	{
+		public void mouseDoubleClick(org.eclipse.swt.events.MouseEvent e) {
+			if (e.button == MouseEvent.BUTTON1)
+			{
+				TableItem[] selectedItems = table.getSelection();
+				if (selectedItems.length == 0)
+					return;
+
+				if (selectedItems[0].getData() instanceof ProfiledGeneric)
+				{
+					ProfiledGeneric pg = (ProfiledGeneric)(selectedItems[0].getData());
+				    if (pg.isEnabled(myGraph.getGraphIndex()))
+				        action("remove"); //$NON-NLS-1$
+				    else
+				        action("add"); //$NON-NLS-1$
+				    action("doubleClick");  //$NON-NLS-1$
+				}
+			}
+		}
+
+		public void mouseDown(org.eclipse.swt.events.MouseEvent e) {
+		}
+
+		public void mouseUp(org.eclipse.swt.events.MouseEvent e) {
+			if (e.button == MouseEvent.BUTTON3) {
+				Menu menu = getTableMenu(table.getShell(), myGraph.getGraphIndex(), myGraph.getDrawMode());
+				menu.setLocation(parent.toDisplay(e.x + table.getLocation().x, e.y + table.getLocation().y));
+				table.setMenu(menu);
+			}
+		}
+	}
+
+	public void setVisualisationColumnVisible(boolean flag) {}
+
+	public void valueChanged(SelectionEvent e) {}
+
+	protected Vector<ProfiledGeneric> setTableItemData(Enumeration<ProfiledGeneric> enu) {
+	    Vector<ProfiledGeneric> tmpItems = new Vector<ProfiledGeneric>();
+
+	    while (enu.hasMoreElements())
+		{
+		    tmpItems.add(enu.nextElement());
+		}
+		return tmpItems;
+	}
+
+	protected void addDrillDownItems(Menu tableMenu, int drawMode)
+	{
+		switch (drawMode)
+		{
+			case Defines.THREADS:
+			{
+				// thread drill down items
+				threadItem        (tableMenu, true);
+				threadBinaryItem  (tableMenu, false);
+				threadFunctionItem(tableMenu, false);
+				break;
+			}
+			case Defines.THREADS_BINARIES:
+			{
+				// thread drill down items
+				threadItem              (tableMenu, false);
+				threadBinaryItem        (tableMenu, true);
+				threadBinaryFunctionItem(tableMenu, false);
+				break;
+			}
+			case Defines.THREADS_BINARIES_FUNCTIONS:
+			{
+				// thread drill down items
+				threadItem              (tableMenu, false);
+				threadBinaryItem        (tableMenu, false);
+				threadBinaryFunctionItem(tableMenu, true);
+				break;
+			}
+			case Defines.THREADS_FUNCTIONS:
+			{
+				// thread drill down items
+				threadItem             (tableMenu, false);
+				threadFunctionItem     (tableMenu, true);
+				newThreadFunctionBinary(tableMenu, false);
+				break;
+			}
+			case Defines.THREADS_FUNCTIONS_BINARIES:
+			{
+				// thread drill down items
+				threadItem             (tableMenu, false);
+				threadFunctionItem     (tableMenu, false);
+				newThreadFunctionBinary(tableMenu, true);
+				break;
+			}
+			case Defines.BINARIES:
+			{
+				// binary drill down items
+				binaryItem        (tableMenu, true);
+				binaryThreadItem  (tableMenu, false);
+				binaryFunctionItem(tableMenu, false);
+				break;
+			}
+			case Defines.BINARIES_THREADS:
+			{
+				// binary drill down items
+				binaryItem              (tableMenu, false);
+				binaryThreadItem        (tableMenu, true);
+				binaryThreadFunctionItem(tableMenu, false);
+				break;
+			}
+			case Defines.BINARIES_THREADS_FUNCTIONS:
+			{
+				// binary drill down items
+				binaryItem              (tableMenu, false);
+				binaryThreadItem        (tableMenu, false);
+				binaryThreadFunctionItem(tableMenu, true);
+				break;
+			}
+			case Defines.BINARIES_FUNCTIONS:
+			{
+				// binary drill down items
+				binaryItem              (tableMenu, false);
+				binaryFunctionItem      (tableMenu, true);
+				binaryFunctionThreadItem(tableMenu, false);
+				break;
+			}
+			case Defines.BINARIES_FUNCTIONS_THREADS:
+			{
+				// binary drill down items
+				binaryItem              (tableMenu, false);
+				binaryFunctionItem      (tableMenu, false);
+				binaryFunctionThreadItem(tableMenu, true);
+				break;
+			}
+			case Defines.FUNCTIONS:
+			{
+				// function drill down items 
+				functionItem      (tableMenu, true);
+				functionThreadItem(tableMenu, false);
+				functionBinaryItem(tableMenu, false);
+				break;
+			}
+			case Defines.FUNCTIONS_THREADS:
+			{
+				// function drill down items 
+				functionItem            (tableMenu, false);
+				functionThreadItem      (tableMenu, true);
+				functionThreadBinaryItem(tableMenu, false);
+				break;
+			}
+			case Defines.FUNCTIONS_THREADS_BINARIES:
+			{
+				// function drill down items 
+				functionItem            (tableMenu, false);
+				functionThreadItem      (tableMenu, false);
+				functionThreadBinaryItem(tableMenu, true);
+				break;
+			}
+			case Defines.FUNCTIONS_BINARIES:
+			{
+				// function drill down items 
+				functionItem            (tableMenu, false);
+				functionBinaryItem      (tableMenu, true);
+				functionBinaryThreadItem(tableMenu, false);
+				break;
+			}
+			case Defines.FUNCTIONS_BINARIES_THREADS:
+			{
+				// function drill down items 
+				functionItem            (tableMenu, false);
+				functionBinaryItem      (tableMenu, false);
+				functionBinaryThreadItem(tableMenu, true);
+				break;
+			}
+			default:
+				break;
+		}
+	}
+
+	/*
+	 * Find if any threads with checkboxes checked
+	 */
+	protected boolean haveCheckedThread(GppTrace trace, int graphIndex)
+	{
+		ProfiledThread pThread;
+		for (ProfiledGeneric pGeneric: trace.getIndexedThreads()) {
+			if (pGeneric instanceof ProfiledThread) {
+				pThread = (ProfiledThread) pGeneric;
+				if (pThread.isEnabled(graphIndex))
+					return true;
+			}
+		}
+		return false;
+	}
+	
+
+	/*
+	 * Find if any binaries with checkboxes checked
+	 */
+	protected boolean haveCheckedBinary(GppTrace trace, int graphIndex)
+	{
+		ProfiledBinary pBinary;
+		for (ProfiledGeneric pGeneric: trace.getIndexedBinaries()) {
+			if (pGeneric instanceof ProfiledBinary) {
+				pBinary = (ProfiledBinary) pGeneric;
+				if (pBinary.isEnabled(graphIndex))
+					return true;
+			}
+		}
+		return false;
+	}
+
+	/*
+	 * Find if any functions with checkboxes checked
+	 */
+	protected boolean haveCheckedFunction(GppTrace trace, int graphIndex)
+	{
+		ProfiledFunction pFunction;
+		for (ProfiledGeneric pGeneric: trace.getIndexedFunctions()) {
+			if (pGeneric instanceof ProfiledFunction) {
+				pFunction = (ProfiledFunction) pGeneric;
+				if (pFunction.isEnabled(graphIndex))
+					return true;
+			}
+		}
+		return false;
+	}
+	
+	/* 
+	 * get list of matching samples based on draw mode 
+	 */
+	private ArrayList<GppSample> getMatchingSamples(int drawMode, GppTrace trace, int startIndex, int endIndex, int graphIndex)
+	{
+		ArrayList<GppSample> samplesArray = new ArrayList<GppSample>(endIndex - startIndex > 1000 ? 1000 : endIndex - startIndex);
+		Vector<ProfiledGeneric> traceThreads   = trace.getIndexedThreads();
+		Vector<ProfiledGeneric> traceBinaries  = trace.getIndexedBinaries();
+		Vector<ProfiledGeneric> traceFunctions = trace.getIndexedFunctions();
+		GppSample[] samples = trace.getSortedGppSamples();
+		GppSample sample;
+
+		switch (drawMode)
+		{
+		case Defines.THREADS:
+			for (int i = startIndex; i < endIndex; i++) {
+				sample = samples[i];
+				ProfiledThread pThread = (ProfiledThread) traceThreads.elementAt(sample.threadIndex);
+				if (pThread.isEnabled(graphIndex))
+					samplesArray.add(sample);
+			}
+			break;
+		case Defines.BINARIES:
+			for (int i = startIndex; i < endIndex; i++) {
+				sample = samples[i];
+				ProfiledBinary pBinary = (ProfiledBinary) traceBinaries.elementAt(sample.binaryIndex);
+				if (pBinary.isEnabled(graphIndex))
+					samplesArray.add(sample);
+			}
+			break;
+		case Defines.FUNCTIONS:
+			for (int i = startIndex; i < endIndex; i++) {
+				sample = samples[i];
+				ProfiledFunction pFunction = (ProfiledFunction) traceFunctions.elementAt(sample.functionIndex);
+				if (pFunction.isEnabled(graphIndex))
+					samplesArray.add(sample);
+			}
+			break;
+		case Defines.THREADS_BINARIES:
+		case Defines.BINARIES_THREADS:
+			for (int i = startIndex; i < endIndex; i++) {
+				sample = samples[i];
+				ProfiledThread pThread = (ProfiledThread) traceThreads.elementAt(sample.threadIndex);
+				if (pThread.isEnabled(graphIndex)) {
+					ProfiledBinary pBinary = (ProfiledBinary) traceBinaries.elementAt(sample.binaryIndex);
+					if (pBinary.isEnabled(graphIndex)) {
+						samplesArray.add(sample);
+					}
+				}
+			}
+			break;
+		case Defines.THREADS_FUNCTIONS:
+		case Defines.FUNCTIONS_THREADS:
+			for (int i = startIndex; i < endIndex; i++) {
+				sample = samples[i];
+				ProfiledThread pThread = (ProfiledThread) traceThreads.elementAt(sample.threadIndex);
+				if (pThread.isEnabled(graphIndex)) {
+					ProfiledFunction pFunction = (ProfiledFunction) traceFunctions.elementAt(sample.functionIndex);
+					if (pFunction.isEnabled(graphIndex)) {
+						samplesArray.add(sample);
+					}
+				}
+			}
+			break;
+		case Defines.BINARIES_FUNCTIONS:
+		case Defines.FUNCTIONS_BINARIES:
+			for (int i = startIndex; i < endIndex; i++) {
+				sample = samples[i];
+				ProfiledBinary pBinary = (ProfiledBinary) traceBinaries.elementAt(sample.binaryIndex);
+				if (pBinary.isEnabled(graphIndex)) {
+					ProfiledFunction pFunction = (ProfiledFunction) traceFunctions.elementAt(sample.functionIndex);
+					if (pFunction.isEnabled(graphIndex)) {
+						samplesArray.add(sample);
+					}
+				}
+			}
+			break;
+		case Defines.THREADS_FUNCTIONS_BINARIES:
+		case Defines.THREADS_BINARIES_FUNCTIONS:
+			for (int i = startIndex; i < endIndex; i++) {
+				sample = samples[i];
+				ProfiledThread pThread = (ProfiledThread) traceThreads.elementAt(sample.threadIndex);
+				if (pThread.isEnabled(graphIndex)) {
+					ProfiledBinary pBinary = (ProfiledBinary) traceBinaries.elementAt(sample.binaryIndex);
+					if (pBinary.isEnabled(graphIndex)) {
+						ProfiledFunction pFunction = (ProfiledFunction) traceFunctions.elementAt(sample.functionIndex);
+						if (pFunction.isEnabled(graphIndex)) {
+							samplesArray.add(sample);
+						}
+					}
+				}
+			}
+			break;
+		}
+		
+		samplesArray.trimToSize();
+		return samplesArray;
+	}
+
+	/*
+	 * return the thread, binary, or function samples selected in the interval 
+	 */
+	protected String getSampleString(int graphIndex, int drawMode, int startIndex, int endIndex)
+	{
+		boolean threads   = false;
+		boolean binaries  = false;
+		boolean functions = false;
+		GppTraceGraph graph = (GppTraceGraph)(this.myGraph);
+		GppTrace trace = (GppTrace)(graph.getTrace());
+
+		// The current graph shows either threads, binaries, or functions
+		switch (drawMode)
+		{
+		case Defines.THREADS:
+		case Defines.BINARIES_THREADS:
+		case Defines.BINARIES_FUNCTIONS_THREADS:
+		case Defines.FUNCTIONS_THREADS:
+		case Defines.FUNCTIONS_BINARIES_THREADS:
+			threads = true;
+			break;
+		case Defines.BINARIES:
+		case Defines.THREADS_BINARIES:
+		case Defines.THREADS_FUNCTIONS_BINARIES:
+		case Defines.FUNCTIONS_BINARIES:
+		case Defines.FUNCTIONS_THREADS_BINARIES:
+			binaries = true;
+			break;
+		case Defines.FUNCTIONS:
+		case Defines.THREADS_FUNCTIONS:
+		case Defines.THREADS_BINARIES_FUNCTIONS:
+		case Defines.BINARIES_FUNCTIONS:
+		case Defines.BINARIES_THREADS_FUNCTIONS:
+			functions = true;
+			break;
+		default:
+			break;
+		}
+
+		int startTime = trace.getStartSampleIndex();
+		int endTime   = trace.getEndSampleIndex();
+		
+		// check if we have returned everything
+		if (startIndex > (endTime - startTime))
+			return null;
+
+		ArrayList<GppSample> matchingSamples = getMatchingSamples(drawMode, trace, startTime, endTime, graphIndex);
+
+		String returnString = ""; //$NON-NLS-1$
+		
+		if (threads) {
+			Vector<ProfiledGeneric> traceThreads   = trace.getIndexedThreads();
+			if (startIndex == 0)
+				returnString = Messages.getString("GenericAddrTable.threadSampleHeading");  //$NON-NLS-1$
+			
+			for (int i = startIndex; i < matchingSamples.size() && i < endIndex; i++) {
+				GppSample sample = matchingSamples.get(i);
+				returnString +=   sample.sampleSynchTime + ",0x" + Long.toHexString(sample.programCounter) + ","	  //$NON-NLS-1$ //$NON-NLS-2$; $NON-NLS-2$;
+								+ traceThreads.get(sample.threadIndex).getNameString() + "\n";  //$NON-NLS-1$
+			}
+		} else if (binaries) {
+			if (startIndex == 0)
+				returnString = Messages.getString("GenericAddrTable.binarySampleHeading");  //$NON-NLS-1$
+			
+			for (int i = startIndex; i < matchingSamples.size() && i < endIndex; i++) {
+				GppSample sample = matchingSamples.get(i);
+				ProfiledBinary binary = (ProfiledBinary) trace.getIndexedBinaries().get(sample.binaryIndex);
+				returnString +=   sample.sampleSynchTime + ",0x" + Long.toHexString(sample.programCounter) + ","	  //$NON-NLS-1$ //$NON-NLS-2$; $NON-NLS-2$;
+								+ binary.getNameString() + "\n";  // $NON-NLS-1$; //$NON-NLS-1$
+			}
+		} else if (functions) {
+			if (startIndex == 0)
+				returnString = Messages.getString("GenericAddrTable.functionSampleHeading");  //$NON-NLS-1$
+			
+			for (int i = startIndex; i < matchingSamples.size() && i < endIndex; i++) {
+				GppSample sample = matchingSamples.get(i);
+				ProfiledFunction function = (ProfiledFunction) trace.getIndexedFunctions().get(sample.functionIndex);
+				returnString +=   sample.sampleSynchTime + ",0x" + Long.toHexString(sample.programCounter) + ",\""	  //$NON-NLS-1$ //$NON-NLS-2$; $NON-NLS-2$;
+								+ function.getNameString() + "\",0x" + Long.toHexString(function.getFunctionAddress()) + "\n";  //$NON-NLS-1$ //$NON-NLS-2$; $NON-NLS-2$;
+			}
+		}
+		
+		return returnString;
+	}
+
+	private void threadItem(Menu menu, boolean chosen) {
+		MenuItem menuItem = new MenuItem(menu, SWT.RADIO);
+		menuItem.setText(Messages.getString("GenericAddrTable.threadOnly"));  //$NON-NLS-1$
+		menuItem.setSelection(chosen);
+		menuItem.addSelectionListener(new SelectionAdapter() { 
+			public void widgetSelected(SelectionEvent e) {
+			    action("thread-only"); //$NON-NLS-1$
+			}
+		});
+	}
+
+	private void threadBinaryItem(Menu menu, boolean chosen) {
+		MenuItem menuItem = new MenuItem(menu, SWT.RADIO);
+		menuItem.setText(Messages.getString("GenericAddrTable.threadBinary"));  //$NON-NLS-1$
+		menuItem.setSelection(chosen);
+		menuItem.addSelectionListener(new SelectionAdapter() { 
+			public void widgetSelected(SelectionEvent e) {
+			    action("thread-binary"); //$NON-NLS-1$
+			}
+		});
+	}
+
+	private void threadBinaryFunctionItem(Menu menu, boolean chosen) {
+		MenuItem menuItem = new MenuItem(menu, SWT.RADIO);
+		menuItem.setText(Messages.getString("GenericAddrTable.threadBinaryFunction"));  //$NON-NLS-1$
+		menuItem.setSelection(chosen);
+		menuItem.addSelectionListener(new SelectionAdapter() { 
+			public void widgetSelected(SelectionEvent e) {
+			    action("thread-binary-function"); //$NON-NLS-1$
+			}
+		});
+	}
+
+	private void threadFunctionItem(Menu menu, boolean chosen) {
+		MenuItem menuItem = new MenuItem(menu, SWT.RADIO);
+		menuItem.setText(Messages.getString("GenericAddrTable.threadFunction"));  //$NON-NLS-1$
+		menuItem.setSelection(chosen);
+		menuItem.addSelectionListener(new SelectionAdapter() { 
+			public void widgetSelected(SelectionEvent e) {
+			    action("thread-function"); //$NON-NLS-1$
+			}
+		});
+	}
+
+	private void newThreadFunctionBinary(Menu menu, boolean chosen) {
+		MenuItem menuItem = new MenuItem(menu, SWT.RADIO);
+		menuItem.setText(Messages.getString("GenericAddrTable.threadFunctionBinary"));  //$NON-NLS-1$
+		menuItem.setSelection(chosen);
+		menuItem.addSelectionListener(new SelectionAdapter() { 
+			public void widgetSelected(SelectionEvent e) {
+			    action("thread-function-binary"); //$NON-NLS-1$
+			}
+		});
+	}
+
+	private void binaryItem(Menu menu, boolean chosen) {
+		MenuItem menuItem = new MenuItem(menu, SWT.RADIO);
+		menuItem.setText(Messages.getString("GenericAddrTable.binaryOnly"));  //$NON-NLS-1$
+		menuItem.setSelection(chosen);
+		menuItem.addSelectionListener(new SelectionAdapter() { 
+			public void widgetSelected(SelectionEvent e) {
+			    action("binary-only"); //$NON-NLS-1$
+			}
+		});
+	}
+
+	private void binaryThreadItem(Menu menu, boolean chosen) {
+		MenuItem menuItem = new MenuItem(menu, SWT.RADIO);
+		menuItem.setText(Messages.getString("GenericAddrTable.binaryThread"));  //$NON-NLS-1$
+		menuItem.setSelection(chosen);
+		menuItem.addSelectionListener(new SelectionAdapter() { 
+			public void widgetSelected(SelectionEvent e) {
+			    action("binary-thread"); //$NON-NLS-1$
+			}
+		});
+	}
+
+	private void binaryThreadFunctionItem(Menu menu, boolean chosen) {
+		MenuItem menuItem = new MenuItem(menu, SWT.RADIO);
+		menuItem.setText(Messages.getString("GenericAddrTable.binaryThreadFunction"));  //$NON-NLS-1$
+		menuItem.setSelection(chosen);
+		menuItem.addSelectionListener(new SelectionAdapter() { 
+			public void widgetSelected(SelectionEvent e) {
+			    action("binary-thread-function"); //$NON-NLS-1$
+			}
+		});
+	}
+
+	private void binaryFunctionItem(Menu menu, boolean chosen) {
+		MenuItem menuItem = new MenuItem(menu, SWT.RADIO);
+		menuItem.setText(Messages.getString("GenericAddrTable.binaryFunction"));  //$NON-NLS-1$
+		menuItem.setSelection(chosen);
+		menuItem.addSelectionListener(new SelectionAdapter() { 
+			public void widgetSelected(SelectionEvent e) {
+			    action("binary-function"); //$NON-NLS-1$
+			}
+		});
+	}
+
+	private void binaryFunctionThreadItem(Menu menu, boolean chosen) {
+		MenuItem menuItem = new MenuItem(menu, SWT.RADIO);
+		menuItem.setText(Messages.getString("GenericAddrTable.binaryFunctionThread"));  //$NON-NLS-1$
+		menuItem.setSelection(chosen);
+		menuItem.addSelectionListener(new SelectionAdapter() { 
+			public void widgetSelected(SelectionEvent e) {
+			    action("binary-function-thread"); //$NON-NLS-1$
+			}
+		});
+	}
+
+	private void functionItem(Menu menu, boolean chosen) {
+		MenuItem menuItem = new MenuItem(menu, SWT.RADIO);
+		menuItem.setText(Messages.getString("GenericAddrTable.functionOnly"));  //$NON-NLS-1$
+		menuItem.setSelection(chosen);
+		menuItem.addSelectionListener(new SelectionAdapter() { 
+			public void widgetSelected(SelectionEvent e) {
+			    action("function-only"); //$NON-NLS-1$
+			}
+		});
+	}
+
+	private void functionThreadItem(Menu menu, boolean chosen) {
+		MenuItem menuItem = new MenuItem(menu, SWT.RADIO);
+		menuItem.setText(Messages.getString("GenericAddrTable.functionThread"));  //$NON-NLS-1$
+		menuItem.setSelection(chosen);
+		menuItem.addSelectionListener(new SelectionAdapter() { 
+			public void widgetSelected(SelectionEvent e) {
+			    action("function-thread"); //$NON-NLS-1$
+			}
+		});
+	}
+
+	private void functionThreadBinaryItem(Menu menu, boolean chosen) {
+		MenuItem menuItem = new MenuItem(menu, SWT.RADIO);
+		menuItem.setText(Messages.getString("GenericAddrTable.functionThreadBinary"));  //$NON-NLS-1$
+		menuItem.setSelection(chosen);
+		menuItem.addSelectionListener(new SelectionAdapter() { 
+			public void widgetSelected(SelectionEvent e) {
+			    action("function-thread-binary"); //$NON-NLS-1$
+			}
+		});
+	}
+
+	private void functionBinaryItem(Menu menu, boolean chosen) {
+		MenuItem menuItem = new MenuItem(menu, SWT.RADIO);
+		menuItem.setText(Messages.getString("GenericAddrTable.functionBinary"));  //$NON-NLS-1$
+		menuItem.setSelection(chosen);
+		menuItem.addSelectionListener(new SelectionAdapter() { 
+			public void widgetSelected(SelectionEvent e) {
+			    action("function-binary"); //$NON-NLS-1$
+			}
+		});
+	}
+
+	private void functionBinaryThreadItem(Menu menu, boolean chosen) {
+		MenuItem menuItem = new MenuItem(menu, SWT.RADIO);
+		menuItem.setText(Messages.getString("GenericAddrTable.functionBinaryThread"));  //$NON-NLS-1$
+		menuItem.setSelection(chosen);
+		menuItem.addSelectionListener(new SelectionAdapter() { 
+			public void widgetSelected(SelectionEvent e) {
+			    action("function-binary-thread"); //$NON-NLS-1$
+			}
+		});
+	}
+	
+	protected String copyDrilldown(int tableCount, Table[] tables, String separator)
+	{	
+		// make sure it's a valid drilldown
+		if (   (tableCount < 2) || (tableCount > 3)
+			|| (tables[0] == null) || (tables[1] == null)
+			|| (tableCount == 2 && tables[2] != null)
+			|| (tableCount == 3 && tables[2] == null))
+			return ""; //$NON-NLS-1$
+		
+		String copyString = ""; //$NON-NLS-1$
+
+		// create the multiple table heading line (e.g., "Threads     Binaries")
+		// space them out based on how many columns are in their table
+		for (int i = 0; i < tableCount; i++) {
+			if (tables[i].getData() instanceof String) {
+				copyString += (String) (tables[i].getData());
+			}
+			for (int j = 0; j < tables[i].getColumnCount(); j++) {
+				copyString += separator;
+			}
+		}
+		copyString += "\n"; //$NON-NLS-1$
+		
+		// create the multiple table column headings
+		for (int i = 0; i < tableCount; i++) {
+			if (i != tableCount - 1) {
+				copyString += copyHeading(tables[i], CHECKBOX_NO_TEXT, separator, separator); //$NON-NLS-1$
+			} else {
+				copyString += copyHeading(tables[i], CHECKBOX_NO_TEXT, separator, "\n"); //$NON-NLS-1$
+			}
+		}
+		
+		// determine the row, column count, and column ordering in each table
+		int rowCount0      = tables[0].getItemCount();
+		int columnCount0   = tables[0].getColumnCount();
+		int[] columnOrder0 = tables[0].getColumnOrder();
+		boolean[] isHex0   = (boolean[]) tables[0].getData("isHex"); //$NON-NLS-1$
+		String emptyRow0 = ""; //$NON-NLS-1$
+
+		int rowCount1      = tables[1].getItemCount();
+		int columnCount1   = tables[1].getColumnCount();
+		int[] columnOrder1 = tables[1].getColumnOrder();
+		boolean[] isHex1   = (boolean[]) tables[1].getData("isHex"); //$NON-NLS-1$
+		String emptyRow1 = ""; //$NON-NLS-1$
+
+		int rowCount2      = tableCount > 2 ? tables[2].getItemCount() : 0;
+		int columnCount2   = tableCount > 2 ? tables[2].getColumnCount() : 0;
+		int[] columnOrder2 = tableCount > 2 ? tables[2].getColumnOrder() : null;
+		boolean[] isHex2   = tableCount > 2 ? ((boolean[]) tables[2].getData("isHex")) : null; //$NON-NLS-1$
+		String emptyRow2 = ""; //$NON-NLS-1$
+
+		// determine the number of multiple table rows (max of any table's rows) 
+		int rowCount = rowCount0 >= rowCount1 ? rowCount0 : rowCount1;
+		rowCount = rowCount > rowCount2 ? rowCount : rowCount2;
+		
+		// generate empty row strings, to speed things up
+		if (rowCount0 < rowCount) {
+			for (int j = 0; j < columnCount0 - 1; j++) {
+				emptyRow0 += separator;
+			}
+		}
+
+		if (rowCount1 < rowCount) {
+			for (int j = 0; j < columnCount1; j++) {
+				emptyRow1 += separator;
+			}
+		}
+
+		if ((tableCount > 2) && (rowCount2 < rowCount)) {
+			for (int j = 0; j < columnCount2; j++) {
+				emptyRow2 += separator;
+			}
+		}
+
+		// generate the rows
+		for (int i = 0; i < rowCount; i++) {
+			if (i < rowCount0) {
+				copyString += copyRow(isHex0, tables[0].getItem(i), CHECKBOX_NO_TEXT, columnCount0, columnOrder0, separator);
+			} else {
+				copyString += emptyRow0;
+			}
+			
+			if (i < rowCount1) {
+				copyString += separator + copyRow(isHex1, tables[1].getItem(i), CHECKBOX_NO_TEXT, columnCount1, columnOrder1, separator);
+			} else {
+				// NOTE: if this is the last table, or the 3rd table has nothing but empty
+				// rows left, we may not need to fill in these fields
+				copyString += emptyRow1;
+			}
+			
+			if (tableCount > 2) {
+				if (i < rowCount2) {
+					copyString += separator + copyRow(isHex2, tables[2].getItem(i), CHECKBOX_NO_TEXT, columnCount2, columnOrder2, separator);
+				} else {
+					// NOTE: we may not need to fill in the empty fields of the last table
+					copyString += emptyRow2;
+				}
+			}
+			
+			copyString += "\n"; //$NON-NLS-1$
+		}
+		
+		return copyString;
+	}
+	
+	// class to pass drilldown tables to the save wizard
+	class SaveDrillDownString implements ISaveTable {
+		private int tableCount;
+		private Table[] tables;
+		private String separator;
+		
+		public SaveDrillDownString(int tableCount, Table[] tables, String separator) {
+			this.tableCount = tableCount;
+			this.tables     = tables;
+			this.separator  = separator;
+		}
+
+		public String getData() {
+			return copyDrilldown(tableCount, tables, separator);
+		}
+	}
+	
+	public Table[] getDrillDownTables()
+	{
+		// copy all tables in a drilldown to the clipboard or save to a file
+		int drawMode = this.myGraph.getDrawMode();
+
+		int tableCount = 0;
+		Table[] tables = new Table[3];
+		
+		// determine which tables are in the drilldown
+		switch (drawMode)
+		{
+		case Defines.THREADS_BINARIES:
+			tables[tableCount++] = this.myGraph.getThreadTable().getTable();
+			tables[tableCount++] = this.myGraph.getBinaryTable().getTable();
+			break;
+		case Defines.THREADS_BINARIES_FUNCTIONS:
+			tables[tableCount++] = this.myGraph.getThreadTable().getTable();
+			tables[tableCount++] = this.myGraph.getBinaryTable().getTable();
+			tables[tableCount++] = this.myGraph.getFunctionTable().getTable();
+			break;
+		case Defines.THREADS_FUNCTIONS:
+			tables[tableCount++] = this.myGraph.getThreadTable().getTable();
+			tables[tableCount++] = this.myGraph.getFunctionTable().getTable();
+			break;
+		case Defines.THREADS_FUNCTIONS_BINARIES:
+			tables[tableCount++] = this.myGraph.getThreadTable().getTable();
+			tables[tableCount++] = this.myGraph.getFunctionTable().getTable();
+			tables[tableCount++] = this.myGraph.getBinaryTable().getTable();
+			break;
+		case Defines.BINARIES_THREADS:
+			tables[tableCount++] = this.myGraph.getBinaryTable().getTable();
+			tables[tableCount++] = this.myGraph.getThreadTable().getTable();
+			break;
+		case Defines.BINARIES_THREADS_FUNCTIONS:
+			tables[tableCount++] = this.myGraph.getBinaryTable().getTable();
+			tables[tableCount++] = this.myGraph.getThreadTable().getTable();
+			tables[tableCount++] = this.myGraph.getFunctionTable().getTable();
+			break;
+		case Defines.BINARIES_FUNCTIONS:
+			tables[tableCount++] = this.myGraph.getBinaryTable().getTable();
+			tables[tableCount++] = this.myGraph.getFunctionTable().getTable();
+			break;
+		case Defines.BINARIES_FUNCTIONS_THREADS:
+			tables[tableCount++] = this.myGraph.getBinaryTable().getTable();
+			tables[tableCount++] = this.myGraph.getFunctionTable().getTable();
+			tables[tableCount++] = this.myGraph.getThreadTable().getTable();
+			break;
+		case Defines.FUNCTIONS_THREADS:
+			tables[tableCount++] = this.myGraph.getFunctionTable().getTable();
+			tables[tableCount++] = this.myGraph.getThreadTable().getTable();
+			break;
+		case Defines.FUNCTIONS_THREADS_BINARIES:
+			tables[tableCount++] = this.myGraph.getFunctionTable().getTable();
+			tables[tableCount++] = this.myGraph.getThreadTable().getTable();
+			tables[tableCount++] = this.myGraph.getBinaryTable().getTable();
+			break;
+		case Defines.FUNCTIONS_BINARIES:
+			tables[tableCount++] = this.myGraph.getFunctionTable().getTable();
+			tables[tableCount++] = this.myGraph.getBinaryTable().getTable();
+			break;
+		case Defines.FUNCTIONS_BINARIES_THREADS:
+			tables[tableCount++] = this.myGraph.getFunctionTable().getTable();
+			tables[tableCount++] = this.myGraph.getBinaryTable().getTable();
+			tables[tableCount++] = this.myGraph.getThreadTable().getTable();
+			break;
+		default:
+		}
+		
+		return tables;
+	}
+    
+    protected void actionCopyOrSaveDrilldown(boolean doCopy, String separator)
+    {
+		Table[] tables = getDrillDownTables();
+		
+		int tableCount = 0;
+		while ((tableCount < tables.length) && (tables[tableCount] != null))
+			tableCount++;
+		
+		
+		if (doCopy) {
+			// change the clipboard contents
+	        Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
+			String copyString = copyDrilldown(tableCount, tables, separator);
+			StringSelection contents = new StringSelection(copyString);
+	        cb.setContents(contents, contents);
+		} else {
+			// save to a file
+			SaveDrillDownString getString = new SaveDrillDownString(tableCount, tables, separator);
+			WizardDialog dialog;
+			Wizard w = new SaveTableWizard(getString);
+			dialog = new WizardDialog(PlatformUI.getWorkbench().getDisplay().getActiveShell(), w);
+	    	dialog.open();
+		}
+    }
+	
+	protected void createDefaultActions()
+	{
+		selectAllAction = new Action("SelectAll") { //$NON-NLS-1$
+			public void run() {
+				action("selectAll");  //$NON-NLS-1$
+			}
+		};
+		selectAllAction.setEnabled(true);
+
+		copyAction = new Action("Copy") { //$NON-NLS-1$
+			public void run() {
+				action("copy");  //$NON-NLS-1$
+			}
+		};
+		copyAction.setEnabled(false);
+
+		copyTableAction = new Action("CopyTable") { //$NON-NLS-1$
+			public void run() {
+				action("copyTable");  //$NON-NLS-1$
+			}
+		};
+		copyTableAction.setEnabled(true);
+		copyTableAction.setId("PICopyTable");  //$NON-NLS-1$
+		copyTableAction.setText(Messages.getString("GenericAddrTable.copyTable"));  //$NON-NLS-1$
+
+		copyDrilldownAction = new Action("CopyDrilldown") {  //$NON-NLS-1$
+			public void run() {
+				action("copyDrilldown");  //$NON-NLS-1$
+			}
+		};
+		copyDrilldownAction.setEnabled(false);
+		copyDrilldownAction.setId("PICopyDrilldown");  //$NON-NLS-1$
+		copyDrilldownAction.setText(Messages.getString("GenericAddrTable.copyDrilldownTables"));  //$NON-NLS-1$
+
+		saveTableAction = new Action("SaveTable") { //$NON-NLS-1$
+			public void run() {
+				action("saveTable");  //$NON-NLS-1$
+			}
+		};
+		saveTableAction.setEnabled(true);
+		saveTableAction.setId("PISaveTable");  //$NON-NLS-1$
+		saveTableAction.setText(Messages.getString("GenericAddrTable.saveTable")); //$NON-NLS-1$
+
+		saveDrilldownAction = new Action("SaveDrilldown") {  //$NON-NLS-1$
+			public void run() {
+				action("saveDrilldown");  //$NON-NLS-1$
+			}
+		};
+		saveDrilldownAction.setEnabled(false);
+		saveDrilldownAction.setId("PISaveDrilldown");  //$NON-NLS-1$
+		saveDrilldownAction.setText(Messages.getString("GenericAddrTable.saveDrilldownTables"));  //$NON-NLS-1$
+
+//		saveSamplesAction = new Action("SaveSamples") { //$NON-NLS-1$
+//			public void run() {
+//				action("saveSamples");  //$NON-NLS-1$
+//			}
+//		};
+//		saveSamplesAction.setEnabled(true);
+//		saveSamplesAction.setId("PISaveAddressSamples");  //$NON-NLS-1$
+//		saveSamplesAction.setText(Messages.getString("GenericAddrTable.23") + sampleType + Messages.getString("GenericAddrTable.24")); //$NON-NLS-1$ //$NON-NLS-2$
+	}
+	
+	public void setIsDrilldown(boolean isDrilldown)
+	{
+		this.isDrilldown = isDrilldown;
+		copyDrilldownAction.setEnabled(isDrilldown);
+		saveDrilldownAction.setEnabled(isDrilldown);
+
+		// may need to clean up stale Edit & File menu entry for PICopyDrilldown and PISaveDrilldown 
+		if (!isDrilldown) {
+			IMenuManager editMenuManager = PIPageEditor.getActionBars().getMenuManager().findMenuUsingPath(IIDEActionConstants.M_EDIT);
+			
+	        if (editMenuManager instanceof SubMenuManager)
+	        {
+	        	IContributionManager editManager = ((SubMenuManager)editMenuManager).getParent();
+	        	ActionContributionItem item;
+	
+				editMenuManager.remove("PICopyDrilldown");  //$NON-NLS-1$
+	        	item = new ActionContributionItem(copyDrilldownAction);
+	        	item.setVisible(true);
+	        	editManager.prependToGroup(IIDEActionConstants.CUT_EXT, item);
+	
+				editMenuManager.remove("PICopyTable");  //$NON-NLS-1$
+	        	copyTableAction.setEnabled(table.getItemCount() > 0);
+	        	item = new ActionContributionItem(copyTableAction);
+	        	item.setVisible(true);
+	        	editManager.prependToGroup(IIDEActionConstants.CUT_EXT, item);
+	        }
+
+			IMenuManager fileMenuManager = PIPageEditor.getActionBars().getMenuManager().findMenuUsingPath(IIDEActionConstants.M_FILE);
+
+	        if (fileMenuManager instanceof SubMenuManager)
+	        {
+	        	IContributionManager fileManager = ((SubMenuManager)fileMenuManager).getParent();
+	        	ActionContributionItem item;
+	
+				fileMenuManager.remove("PISaveTable");  //$NON-NLS-1$
+	        	saveTableAction.setEnabled(table.getItemCount() > 0);
+	        	item = new ActionContributionItem(saveTableAction);
+	        	item.setVisible(true);
+	        	fileManager.insertAfter("saveAll", item); //$NON-NLS-1$
+	        	
+				fileMenuManager.remove("PISaveDrilldown");  //$NON-NLS-1$
+	        	item = new ActionContributionItem(saveDrilldownAction);
+	        	item.setVisible(true);
+	        	fileManager.insertAfter("PISaveTable", item); //$NON-NLS-1$
+	        	fileManager.update(true);
+	        }
+		}
+	}
+
+	protected MenuItem getCopyDrilldownItem(Menu menu, boolean enabled) {
+	    MenuItem copyDrilldownItem = new MenuItem(menu, SWT.PUSH);
+
+	    copyDrilldownItem.setText(Messages.getString("GenericAddrTable.copyDrilldownTables"));  //$NON-NLS-1$
+		copyDrilldownItem.setEnabled(enabled);
+		
+		if (enabled) {
+			copyDrilldownItem.addSelectionListener(new SelectionAdapter() { 
+				public void widgetSelected(SelectionEvent e) {
+					action("copyDrilldown"); //$NON-NLS-1$
+				}
+			});
+		}
+
+		return copyDrilldownItem;
+	}
+
+	protected MenuItem getSaveDrilldownItem(Menu menu, boolean enabled) {
+	    MenuItem saveDrilldownItem = new MenuItem(menu, SWT.PUSH);
+
+	    saveDrilldownItem.setText(Messages.getString("GenericAddrTable.saveDrilldownTables"));  //$NON-NLS-1$
+		saveDrilldownItem.setEnabled(enabled);
+		
+		if (enabled) {
+			saveDrilldownItem.addSelectionListener(new SelectionAdapter() { 
+				public void widgetSelected(SelectionEvent e) {
+					action("saveDrilldown"); //$NON-NLS-1$
+				}
+			});
+		}
+
+		return saveDrilldownItem;
+	}
+
+	protected class AddrTableFocusListener implements FocusListener
+	{
+		IAction oldSelectAllAction = null;
+		IAction oldCopyAction = null;
+
+		public void focusGained(org.eclipse.swt.events.FocusEvent arg0) {
+			IActionBars bars = PIPageEditor.getActionBars();
+			
+			// modify what is executed when Select All and Copy are called from the Edit menu
+			oldSelectAllAction = bars.getGlobalActionHandler(ActionFactory.SELECT_ALL.getId());
+			oldCopyAction = bars.getGlobalActionHandler(ActionFactory.COPY.getId());
+
+			bars.setGlobalActionHandler(ActionFactory.COPY.getId(), copyAction);
+			bars.setGlobalActionHandler(ActionFactory.SELECT_ALL.getId(), selectAllAction);
+
+			copyAction.setEnabled(table.getSelectionCount() > 0);
+			selectAllAction.setEnabled(table.getItemCount() > 0);
+			bars.updateActionBars();
+			
+			// add to the Edit menu
+	        IMenuManager editMenuManager = bars.getMenuManager().findMenuUsingPath(IIDEActionConstants.M_EDIT);
+
+	        if (editMenuManager instanceof SubMenuManager)
+	        {
+	        	IContributionManager editManager = ((SubMenuManager)editMenuManager).getParent();
+	        	ActionContributionItem item;
+
+				editMenuManager.remove("PICopyDrilldown");  //$NON-NLS-1$
+	        	item = new ActionContributionItem(copyDrilldownAction);
+	        	item.setVisible(true);
+	        	editManager.prependToGroup(IIDEActionConstants.CUT_EXT, item);
+
+				editMenuManager.remove("PICopyTable");  //$NON-NLS-1$
+	        	copyTableAction.setEnabled(table.getItemCount() > 0);
+	        	item = new ActionContributionItem(copyTableAction);
+	        	item.setVisible(true);
+	        	editManager.prependToGroup(IIDEActionConstants.CUT_EXT, item);
+	        }
+			
+			// add to the File menu
+	        IMenuManager fileMenuManager = bars.getMenuManager().findMenuUsingPath(IIDEActionConstants.M_FILE);
+
+	        if (fileMenuManager instanceof SubMenuManager)
+	        {
+	        	IContributionManager fileManager = ((SubMenuManager)fileMenuManager).getParent();
+	        	ActionContributionItem item;
+
+				fileMenuManager.remove("PISaveTable");  //$NON-NLS-1$
+	        	saveTableAction.setEnabled(table.getItemCount() > 0);
+	        	item = new ActionContributionItem(saveTableAction);
+	        	item.setVisible(true);
+	        	fileManager.insertAfter("saveAll", item); //$NON-NLS-1$
+
+				fileMenuManager.remove("PISaveDrilldown");  //$NON-NLS-1$
+	        	item = new ActionContributionItem(saveDrilldownAction);
+	        	item.setVisible(true);
+	        	fileManager.insertAfter("PISaveTable", item); //$NON-NLS-1$
+	        }
+		}
+
+		public void focusLost(org.eclipse.swt.events.FocusEvent arg0) {
+			IActionBars bars = PIPageEditor.getActionBars();
+			bars.setGlobalActionHandler(ActionFactory.COPY.getId(), oldCopyAction);
+			bars.setGlobalActionHandler(ActionFactory.SELECT_ALL.getId(), oldSelectAllAction);
+			bars.updateActionBars();
+
+			SubMenuManager editMenuManager = (SubMenuManager) PIPageEditor.getMenuManager().find(IIDEActionConstants.M_EDIT);
+			editMenuManager.remove("PICopyTable");  //$NON-NLS-1$
+			editMenuManager.remove("PICopyDrilldown");  //$NON-NLS-1$
+
+			SubMenuManager fileMenuManager = (SubMenuManager) PIPageEditor.getMenuManager().find(IIDEActionConstants.M_FILE);
+			fileMenuManager.remove("PISaveTable");  //$NON-NLS-1$
+			fileMenuManager.remove("PISaveDrilldown");  //$NON-NLS-1$
+		}
+	}
+}