sysperfana/perfinvestigator/com.nokia.carbide.cpp.pi.address/src/com/nokia/carbide/cpp/pi/address/GppTraceGraph.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/GppTraceGraph.java	Thu Feb 11 15:32:31 2010 +0200
@@ -0,0 +1,2355 @@
+/*
+ * 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: 
+ *
+ */
+
+/*
+ * GppTraceGraph.java
+ */
+package com.nokia.carbide.cpp.pi.address;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Vector;
+
+import org.eclipse.draw2d.FigureCanvas;
+import org.eclipse.draw2d.Graphics;
+import org.eclipse.draw2d.MouseEvent;
+import org.eclipse.draw2d.MouseListener;
+import org.eclipse.draw2d.MouseMotionListener;
+import org.eclipse.draw2d.Panel;
+import org.eclipse.jface.viewers.CheckboxTableViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MouseMoveListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.FormLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Sash;
+
+import com.nokia.carbide.cpp.internal.pi.analyser.NpiInstanceRepository;
+import com.nokia.carbide.cpp.internal.pi.analyser.ProfileVisualiser;
+import com.nokia.carbide.cpp.internal.pi.model.GenericSampledTrace;
+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.model.ProfiledThreshold;
+import com.nokia.carbide.cpp.internal.pi.visual.Defines;
+import com.nokia.carbide.cpp.internal.pi.visual.GenericTable;
+import com.nokia.carbide.cpp.internal.pi.visual.GenericTraceGraph;
+import com.nokia.carbide.cpp.internal.pi.visual.GraphComposite;
+import com.nokia.carbide.cpp.internal.pi.visual.PIEvent;
+import com.nokia.carbide.cpp.internal.pi.visual.PIEventListener;
+import com.nokia.carbide.cpp.internal.pi.visual.PIVisualSharedData;
+import com.nokia.carbide.cpp.pi.editors.PIPageEditor;
+import com.nokia.carbide.cpp.pi.util.ColorPalette;
+
+
+public class GppTraceGraph extends GenericTraceGraph implements ActionListener, 
+																FocusListener, 
+																PIEventListener,
+																MouseMotionListener,
+																MouseListener,
+																MouseMoveListener
+{
+	private GppTraceGraph thisTraceGraph;
+	
+	// amount of space at bottom of graph to contain things like x-axis units and button icons
+	public static final int xLegendHeight = 50;
+	
+	// When the graph is drawn, this is the finest granularity drawn. E.g., assume
+	// a granularity of 100, and a sample every ms. If the 1st function draw appears
+	// in 5 samples from 101ms to 200ms and 10 samples from 200ms to 300ms then the
+	// graph will show a point at height 5 at time 200 connected by a line to a
+	// point at height 10 at time 300.
+	private static int granularityValue = 100;
+	
+	private GppVisualiserPanel vPanel;
+
+	/*
+	 *  Depending on this trace graph's graphIndex, one of these will be
+	 *  the base table, and others will be derived from its selections.
+	 *  The other tables will appear and disappear based on drawMode.
+	 *  
+	 *  E.g., say that for graphIndex = 0, the base table is threadTable.
+	 *  Then this graph can represent the draw modes of:
+	 *  	THREADS
+	 *  	THREADS_BINARIES
+	 *  	THREADS_BINARIES_FUNCTIONS
+	 *  	THREADS_FUNCTIONS
+	 *  	THREADS_FUNCTIONS_BINARIES
+	 */
+	private AddrThreadTable   threadTable;
+	private AddrBinaryTable   binaryTable;
+	private AddrFunctionTable functionTable;
+
+	/*
+	 *	Depending on this trace graph's graphIndex, one of these will match
+	 *	the entire trace's profiled vector, while the others will be derived
+	 *	from drilldown selections. The other vectors will only be meaningful
+	 *  depending on the drawMode.
+	 */
+	private Vector<ProfiledGeneric> profiledThreads   = new Vector<ProfiledGeneric>();
+	private Vector<ProfiledGeneric> profiledBinaries  = new Vector<ProfiledGeneric>();
+	private Vector<ProfiledGeneric> profiledFunctions = new Vector<ProfiledGeneric>();
+	
+	private Vector<ProfiledGeneric> sortedProfiledThreads   = new Vector<ProfiledGeneric>();
+	private Vector<ProfiledGeneric> sortedProfiledBinaries  = new Vector<ProfiledGeneric>();
+	private Vector<ProfiledGeneric> sortedProfiledFunctions = new Vector<ProfiledGeneric>();
+	
+	private ProfiledThreshold thresholdThread   = new ProfiledThreshold("dummy[0]::dummy_0"); //$NON-NLS-1$
+	private ProfiledThreshold thresholdBinary   = new ProfiledThreshold("\\dummy"); //$NON-NLS-1$
+	private ProfiledThreshold thresholdFunction = new ProfiledThreshold("dummy::dummy()"); //$NON-NLS-1$
+
+	// when multiple tables are visible, they are separated by sashes
+	private Sash leftSash;
+	private Sash rightSash;
+
+	public static final int NOFILL       = 0;
+	public static final int FILLSELECTED = 1;
+	public static final int FILLALL      = 2;
+	public static final int BAR_MODE_ON  = 3;
+	public static final int BAR_MODE_OFF = 4;
+		
+	private int drawMode = Defines.THREADS;
+	public int barMode   = BAR_MODE_OFF;
+	
+	private int uid;
+	
+	private static class BarGraphData
+	{
+		public int x;
+		public Color color;
+	}
+	
+	private Vector<BarGraphData> barGraphData;
+	
+	public GppTraceGraph(int graphIndex, GppTrace trace, int uid)
+	{
+		super((GenericSampledTrace)trace);
+		
+		int granularityValue = trace.samples.size() > GppTraceGraph.granularityValue ? GppTraceGraph.granularityValue : trace.samples.size();  
+		
+		this.thisTraceGraph = this;
+		this.graphIndex     = graphIndex;
+		
+		// create the graph's 3 table objects - without any table items yet
+		ProfileVisualiser pV = NpiInstanceRepository.getInstance().getProfilePage(uid, graphIndex);
+		Composite holdTables = new Composite(pV.getBottomComposite(), SWT.NONE);
+		holdTables.setLayout(new FormLayout());
+
+		this.threadTable   = new AddrThreadTable(this, holdTables);
+		this.binaryTable   = new AddrBinaryTable(this, holdTables);
+		this.functionTable = new AddrFunctionTable(this, holdTables);
+		
+		this.uid = uid;
+
+		Label graphTitle = pV.getTitle();
+		Label graphTitle2 = pV.getTitle2();
+		if 	(graphTitle2 != null)
+			graphTitle2.setText(""); //$NON-NLS-1$
+
+		// initialize the threshold counts
+		int totalSampleCount = trace.getSampleAmount();
+		NpiInstanceRepository.getInstance().setPersistState(uid, "com.nokia.carbide.cpp.pi.address.thresholdCountThread", new Integer(new Double(totalSampleCount * (Double)NpiInstanceRepository.getInstance().getPersistState(uid, "com.nokia.carbide.cpp.pi.address.thresholdLoadThread") + 0.5).intValue())); //$NON-NLS-1$ //$NON-NLS-2$
+		NpiInstanceRepository.getInstance().setPersistState(uid, "com.nokia.carbide.cpp.pi.address.thresholdCountBinary", new Integer(new Double(totalSampleCount * (Double)NpiInstanceRepository.getInstance().getPersistState(uid, "com.nokia.carbide.cpp.pi.address.thresholdLoadBinary") + 0.5).intValue())); //$NON-NLS-1$ //$NON-NLS-2$
+		NpiInstanceRepository.getInstance().setPersistState(uid, "com.nokia.carbide.cpp.pi.address.thresholdCountFunction", new Integer(new Double(totalSampleCount * (Double)NpiInstanceRepository.getInstance().getPersistState(uid, "com.nokia.carbide.cpp.pi.address.thresholdLoadFunction") + 0.5).intValue())); //$NON-NLS-1$ //$NON-NLS-2$
+		
+		int samplingInterval = (Integer) NpiInstanceRepository.getInstance().activeUidGetPersistState("com.nokia.carbide.cpp.pi.address.samplingInterval"); //$NON-NLS-1$
+
+		// initialize the threshold items
+		thresholdThread.setColor(trace.getThreadColorPalette().getColor(thresholdThread.getNameString()));
+		thresholdThread.setActivityMarkCount((trace.samples.size() + granularityValue) / granularityValue + 1);
+		for (int i = 0; i < trace.samples.size() + granularityValue; i += granularityValue)
+		{
+			thresholdThread.zeroActivityMarkValues(i * samplingInterval);
+		}
+		thresholdBinary.setColor(trace.getBinaryColorPalette().getColor(thresholdBinary.getNameString()));
+		thresholdBinary.setActivityMarkCount((trace.samples.size() + granularityValue) / granularityValue + 1);
+		for (int i = 0; i < trace.samples.size() + granularityValue; i += granularityValue)
+		{
+			thresholdBinary.zeroActivityMarkValues(i * samplingInterval);
+		}
+		thresholdFunction.setColor(trace.getFunctionColorPalette().getColor(thresholdFunction.getNameString()));
+		thresholdFunction.setActivityMarkCount((trace.samples.size() + granularityValue) / granularityValue + 1);
+		for (int i = 0; i < trace.samples.size() + granularityValue; i += granularityValue)
+		{
+			thresholdFunction.zeroActivityMarkValues(i * samplingInterval);
+		}
+
+		// all the trace data is known, and you have it sorted 3 different ways
+		// so set the drawmode, create the page's base table, and set the graph title
+		if (graphIndex == PIPageEditor.THREADS_PAGE) {
+			this.drawMode = Defines.THREADS;
+
+			// tables will show threads in decreasing total sample order, but
+			// then put them back in increasing sample order so that the graph
+			// shows most common (e.g., EKern) threads on top
+			this.profiledThreads.clear();
+			for (int i = trace.getSortedThreads().size() - 1; i >= 0; i--)
+				this.profiledThreads.add(trace.getSortedThreads().get(i));
+			filterSortedByThreshold(graphIndex, 
+									(Integer)NpiInstanceRepository.getInstance().getPersistState(uid, "com.nokia.carbide.cpp.pi.address.thresholdCountThread"), //$NON-NLS-1$
+									thresholdThread, this.profiledThreads);
+			this.threadTable.setTableViewer(Defines.THREADS);
+
+			this.profiledThreads = trace.getSortedThreads();
+			graphTitle.setText(Messages.getString("GppTraceGraph.threadLoad"));  //$NON-NLS-1$
+		} else
+		if (graphIndex == PIPageEditor.BINARIES_PAGE) {
+			this.drawMode = Defines.BINARIES;
+
+			// tables will show binaries in decreasing total sample order, but
+			// then put them back in increasing sample order so that the graph
+			// shows most common (e.g., EKern) binaries on top
+			this.profiledBinaries.clear();
+			for (int i = trace.getSortedBinaries().size() - 1; i >= 0; i--)
+				this.profiledBinaries.add(trace.getSortedBinaries().get(i));
+			filterSortedByThreshold(graphIndex, (Integer)NpiInstanceRepository.getInstance().getPersistState(uid, "com.nokia.carbide.cpp.pi.address.thresholdCountBinary"), //$NON-NLS-1$
+								thresholdBinary, this.profiledBinaries);
+			this.binaryTable.setTableViewer(Defines.BINARIES);
+
+			this.profiledBinaries = trace.getSortedBinaries();
+			graphTitle.setText(Messages.getString("GppTraceGraph.binaryLoad"));  //$NON-NLS-1$
+		} else
+		if (graphIndex == PIPageEditor.FUNCTIONS_PAGE) {
+			this.drawMode = Defines.FUNCTIONS;
+
+			// tables will show functions in decreasing total sample order, but
+			// then put them back in increasing sample order so that the graph
+			// shows most common (e.g., EKern) functions on top
+			this.profiledFunctions.clear();
+			for (int i = trace.getSortedFunctions().size() - 1; i >= 0; i--)
+				this.profiledFunctions.add(trace.getSortedFunctions().get(i));
+			filterSortedByThreshold(graphIndex, (Integer)NpiInstanceRepository.getInstance().getPersistState(uid, "com.nokia.carbide.cpp.pi.address.thresholdCountFunction"), //$NON-NLS-1$
+								thresholdFunction, this.profiledFunctions);
+			this.functionTable.setTableViewer(Defines.FUNCTIONS);
+
+			this.profiledFunctions = trace.getSortedFunctions();
+			graphTitle.setText(Messages.getString("GppTraceGraph.FunctionLoad"));  //$NON-NLS-1$
+		} else
+		{
+			try {
+				throw new Exception(Messages.getString("GppTraceGraph.traceGraphInternalErrorIn"));  //$NON-NLS-1$
+			} catch (Exception e) {
+				e.printStackTrace();
+			}
+		}
+		
+		// since the trace can be shown any of 3 ways (by thread, by binary, or
+		// by function), make sure that all 3 are ready for display
+		// Sse sorted vector to be consistent with other call to genericRefreshCumulativeThreadTable()
+		// fix issue with wrong color on newly opened npi file before a change in the table
+		if (this.profiledThreads.size() > 0) {
+			genericRefreshCumulativeThreadTable(this.profiledThreads.elements());
+			genericRefreshCumulativeThreadTable(this.sortedProfiledThreads.elements());
+		}
+		if (this.profiledBinaries.size() > 0) {
+			genericRefreshCumulativeThreadTable(this.profiledBinaries.elements());
+			genericRefreshCumulativeThreadTable(this.sortedProfiledBinaries.elements());
+		}
+		if (this.profiledFunctions.size() > 0) {
+			genericRefreshCumulativeThreadTable(this.profiledFunctions.elements());
+			genericRefreshCumulativeThreadTable(this.sortedProfiledFunctions.elements());
+		}
+		
+		if (   this.profiledThreads.size() <= 0
+			&& this.profiledBinaries.size() <= 0
+			&& this.profiledFunctions.size() <= 0) {
+			try {
+				throw new Exception(Messages.getString("GppTraceGraph.traceGraphInternalErrorAt"));  //$NON-NLS-1$
+			} catch (Exception e) {
+				e.printStackTrace();
+			}
+		}
+
+		this.vPanel = new GppVisualiserPanel(this);
+	}
+	
+	/*
+	 * Combine all vectors elements that are below the threshold into a single
+	 * vector element. Assumes that the input vector is sorted by decreasing sample count.
+	 */
+	private void filterSortedByThreshold(int graphIndex, int thresholdCount, ProfiledThreshold pThreshold, Vector<ProfiledGeneric> pGenerics)
+	{
+		// count and remove items below the threshold 
+		for (int i = pGenerics.size() - 1; i >= 0; i--) {
+			if (pGenerics.elementAt(i).getTotalSampleCount() < thresholdCount) {
+				pThreshold.addItem(graphIndex, pGenerics.elementAt(i), 0);
+				pGenerics.removeElementAt(i);
+			} else {
+				break;
+			}
+		}
+	}
+
+	public GppTrace getGppTrace() {
+		return (GppTrace)this.getTrace();
+	}
+
+	public int getGraphIndex()
+	{
+		return this.graphIndex;
+	}
+
+	public void piEventReceived(PIEvent be)
+	{
+		switch (be.getType())
+		{
+			// determine the threads that can be shown, and get rid of all drilldowns
+			case PIEvent.THRESHOLD_THREAD_CHANGED:
+				if (this.getGraphIndex() == PIPageEditor.THREADS_PAGE)
+					this.getThreadTable().action("changeThresholdThread"); //$NON-NLS-1$
+				switch (this.drawMode) {
+				case Defines.THREADS:
+				case Defines.THREADS_FUNCTIONS:
+				case Defines.THREADS_FUNCTIONS_BINARIES:
+				case Defines.THREADS_BINARIES:
+				case Defines.THREADS_BINARIES_FUNCTIONS:
+				case Defines.BINARIES_THREADS:
+				case Defines.BINARIES_THREADS_FUNCTIONS:
+				case Defines.BINARIES_FUNCTIONS_THREADS:
+				case Defines.FUNCTIONS_THREADS:
+				case Defines.FUNCTIONS_THREADS_BINARIES:
+				case Defines.FUNCTIONS_BINARIES_THREADS:
+					this.setGraphImageChanged(true);
+				default:
+					break;
+			}
+				break;
+			case PIEvent.THRESHOLD_BINARY_CHANGED:
+				if (this.getGraphIndex() == PIPageEditor.BINARIES_PAGE)
+					this.getBinaryTable().action("changeThresholdBinary"); //$NON-NLS-1$
+				switch (this.drawMode) {
+				case Defines.THREADS_FUNCTIONS_BINARIES:
+				case Defines.THREADS_BINARIES:
+				case Defines.THREADS_BINARIES_FUNCTIONS:
+				case Defines.BINARIES:
+				case Defines.BINARIES_THREADS:
+				case Defines.BINARIES_THREADS_FUNCTIONS:
+				case Defines.BINARIES_FUNCTIONS:
+				case Defines.BINARIES_FUNCTIONS_THREADS:
+				case Defines.FUNCTIONS_THREADS_BINARIES:
+				case Defines.FUNCTIONS_BINARIES:
+				case Defines.FUNCTIONS_BINARIES_THREADS:
+					this.setGraphImageChanged(true);
+				default:
+					break;
+			}
+				break;
+			case PIEvent.THRESHOLD_FUNCTION_CHANGED:
+				if (this.getGraphIndex() == PIPageEditor.FUNCTIONS_PAGE)
+					this.getFunctionTable().action("changeThresholdFunction"); //$NON-NLS-1$
+				switch (this.drawMode) {
+				case Defines.THREADS_FUNCTIONS:
+				case Defines.THREADS_FUNCTIONS_BINARIES:
+				case Defines.THREADS_BINARIES_FUNCTIONS:
+				case Defines.BINARIES_THREADS_FUNCTIONS:
+				case Defines.BINARIES_FUNCTIONS:
+				case Defines.BINARIES_FUNCTIONS_THREADS:
+				case Defines.FUNCTIONS:
+				case Defines.FUNCTIONS_THREADS:
+				case Defines.FUNCTIONS_THREADS_BINARIES:
+				case Defines.FUNCTIONS_BINARIES:
+				case Defines.FUNCTIONS_BINARIES_THREADS:
+					this.setGraphImageChanged(true);
+				default:
+					break;
+			}
+				break;
+			// when the selection area changes, change the percent loads
+			// and the sample counts in all tables of this GPP graph
+			case PIEvent.SELECTION_AREA_CHANGED:
+				// this is the first GPP graph to be told of the selection area change,
+				// so it gathers the overall trace information
+				GppTrace trace = (GppTrace)this.getTrace();
+				trace.setSelectedArea();
+				
+				// take care of the threshold members
+				int sampleCount = 0;
+				int thresholdCount;
+				
+				if (graphIndex == PIPageEditor.THREADS_PAGE) {
+					thresholdCount = (Integer)NpiInstanceRepository.getInstance().getPersistState(uid, "com.nokia.carbide.cpp.pi.address.thresholdCountThread"); //$NON-NLS-1$
+					if (thresholdCount > 0) {
+						for (int i = 0; i < profiledThreads.size(); i++)
+							if (profiledThreads.elementAt(i).getTotalSampleCount() < thresholdCount)
+								sampleCount += profiledThreads.elementAt(i).getSampleCount(graphIndex);
+						thresholdThread.setSampleCount(this.graphIndex, sampleCount);
+					}
+				} else if (graphIndex == PIPageEditor.BINARIES_PAGE) {
+					thresholdCount = (Integer)NpiInstanceRepository.getInstance().getPersistState(uid, "com.nokia.carbide.cpp.pi.address.thresholdCountBinary"); //$NON-NLS-1$
+					if (thresholdCount > 0) {
+						for (int i = 0; i < profiledBinaries.size(); i++)
+							if (profiledBinaries.elementAt(i).getTotalSampleCount() < thresholdCount)
+								sampleCount += profiledBinaries.elementAt(i).getSampleCount(graphIndex);
+						thresholdBinary.setSampleCount(this.graphIndex, sampleCount);
+					}
+				} else if (graphIndex == PIPageEditor.FUNCTIONS_PAGE) {
+					thresholdCount = (Integer)NpiInstanceRepository.getInstance().getPersistState(uid, "com.nokia.carbide.cpp.pi.address.thresholdCountFunction"); //$NON-NLS-1$
+					if (thresholdCount > 0) {
+						for (int i = 0; i < profiledFunctions.size(); i++)
+							if (profiledFunctions.elementAt(i).getTotalSampleCount() < thresholdCount)
+								sampleCount += profiledFunctions.elementAt(i).getSampleCount(graphIndex);
+						thresholdFunction.setSampleCount(this.graphIndex, sampleCount);
+					}
+				}
+
+				double startTime = PIPageEditor.currentPageEditor().getStartTime();
+				double endTime   = PIPageEditor.currentPageEditor().getEndTime();
+				
+				// send this message to the 2 other GPP graphs
+				PIEvent be2 = new PIEvent(be.getValueObject(),
+						PIEvent.SELECTION_AREA_CHANGED2);
+				
+				// update the selection area shown
+				for (int i = 0; i < 3; i++)
+				{
+					GppTraceGraph graph = trace.getGppGraph(i, getUid());
+
+					if (graph != this) {
+						graph.piEventReceived(be2);
+						// once per graph, update the selection interval shown
+						graph.getCompositePanel().getVisualiser().getTimeString().setText(ProfileVisualiser.getTimeInterval(startTime, endTime));
+					}
+					
+					// change the graph's selected time interval
+					graph.setSelectionStart((double) startTime * 1000);
+					graph.setSelectionEnd((double) endTime * 1000);
+					graph.parentComponent.setSelectionFields((int)(startTime * 1000), (int)(endTime * 1000));
+				}
+
+				this.parentComponent.getSashForm().redraw();
+				be = be2;
+				// FALL THROUGH
+			case PIEvent.SELECTION_AREA_CHANGED2:
+			{
+				// this code lets each graph's base thread/binary/function table update the other tables
+				switch (drawMode)
+				{
+					case Defines.THREADS:
+					case Defines.THREADS_FUNCTIONS:
+					case Defines.THREADS_FUNCTIONS_BINARIES:
+					case Defines.THREADS_BINARIES:
+					case Defines.THREADS_BINARIES_FUNCTIONS:
+				    {
+				        this.threadTable.piEventReceived(be);
+				        break;
+				    }
+					case Defines.BINARIES:
+					case Defines.BINARIES_THREADS:
+					case Defines.BINARIES_THREADS_FUNCTIONS:
+					case Defines.BINARIES_FUNCTIONS:
+					case Defines.BINARIES_FUNCTIONS_THREADS:
+					{
+				        this.binaryTable.piEventReceived(be);
+						break;
+					}
+					case Defines.FUNCTIONS:
+					case Defines.FUNCTIONS_THREADS:
+					case Defines.FUNCTIONS_THREADS_BINARIES:
+					case Defines.FUNCTIONS_BINARIES:
+					case Defines.FUNCTIONS_BINARIES_THREADS:
+					{
+				        this.functionTable.piEventReceived(be);
+						break;
+					}
+				}
+
+				this.vPanel.refreshCumulativeThreadTable();
+				this.setGraphImageChanged(true);	// any selection change to drill down will change graph
+				this.repaint();
+				break;
+			}
+			
+			// in the graph, show all values from the rightmost table
+			case PIEvent.SET_FILL_ALL_THREADS:
+				this.setGraphImageChanged(true);	// any selection change to drill down will change graph
+				this.vPanel.piEventReceived(be);
+				break;
+
+			// in the graph, don't fill between the lines will the color of
+			// the line above
+			case PIEvent.SET_FILL_OFF:
+				this.setGraphImageChanged(true);	// any selection change to drill down will change graph
+				this.vPanel.piEventReceived(be);
+				break;
+
+			// in the graph, show bars
+			case PIEvent.GPP_SET_BAR_GRAPH_ON:
+				this.vPanel.piEventReceived(be);
+				break;
+
+			// in the graph, show polylines 
+			case PIEvent.GPP_SET_BAR_GRAPH_OFF:
+				this.vPanel.piEventReceived(be);
+				break;
+
+			// in the graph, show only the values from selected rows in the
+			// rightmost table
+			case PIEvent.SET_FILL_SELECTED_THREAD:
+				this.setGraphImageChanged(true);	// any selection change to drill down will change graph
+				this.vPanel.piEventReceived(be);
+				break;
+
+			// Redraw the graph because the thread table's selected values have changed.
+			// The thread table is handled (setting of array of selected threads
+			// and table redraw) by the table selection listener or mouse listener.
+			case PIEvent.CHANGED_THREAD_TABLE:
+				switch (drawMode)
+				{
+					case Defines.THREADS_BINARIES:
+					case Defines.THREADS_BINARIES_FUNCTIONS:
+					case Defines.THREADS_FUNCTIONS:
+					case Defines.THREADS_FUNCTIONS_BINARIES:
+					{
+						this.threadTable.piEventReceived(be);
+						break;
+					}
+					case Defines.BINARIES_THREADS_FUNCTIONS:
+					{
+						this.binaryTable.piEventReceived(be);
+						break;
+					}
+					case Defines.FUNCTIONS_THREADS_BINARIES:
+					{
+						this.functionTable.piEventReceived(be);
+						break;
+					}
+					case Defines.THREADS:
+					case Defines.BINARIES:
+					case Defines.BINARIES_THREADS:
+					case Defines.BINARIES_FUNCTIONS:
+					case Defines.BINARIES_FUNCTIONS_THREADS:
+					case Defines.FUNCTIONS:
+					case Defines.FUNCTIONS_THREADS:
+					case Defines.FUNCTIONS_BINARIES:
+					case Defines.FUNCTIONS_BINARIES_THREADS:
+					default:
+						break;
+				}
+
+				this.vPanel.refreshCumulativeThreadTable();
+				this.repaint();
+			    //if fill selected, the graph is drawn again
+				this.vPanel.piEventReceived(be);
+				break;
+
+			// Redraw the graph because the binary table's selected values have changed.
+			// The binary table is handled (setting of array of selected binaries
+			// and table redraw) by the table selection listener or mouse listener.
+			case PIEvent.CHANGED_BINARY_TABLE:
+				switch(drawMode)
+				{
+					case Defines.BINARIES_THREADS:
+					case Defines.BINARIES_THREADS_FUNCTIONS:
+					case Defines.BINARIES_FUNCTIONS:
+					case Defines.BINARIES_FUNCTIONS_THREADS:
+					{
+						this.binaryTable.piEventReceived(be);
+						break;
+					}
+					case Defines.THREADS_BINARIES_FUNCTIONS:
+					{
+						this.threadTable.piEventReceived(be);
+						break;
+					}
+					case Defines.FUNCTIONS_BINARIES_THREADS:
+					{
+						this.functionTable.piEventReceived(be);
+						break;
+					}
+					case Defines.THREADS:
+					case Defines.THREADS_BINARIES:
+					case Defines.THREADS_FUNCTIONS:
+					case Defines.THREADS_FUNCTIONS_BINARIES:
+					case Defines.BINARIES:
+					case Defines.FUNCTIONS:
+					case Defines.FUNCTIONS_THREADS:
+					case Defines.FUNCTIONS_THREADS_BINARIES:
+					case Defines.FUNCTIONS_BINARIES:
+					default:
+						break;
+				}
+
+				this.vPanel.refreshCumulativeThreadTable();
+				this.repaint();
+			    //if fill selected, the graph is drawn again
+				this.vPanel.piEventReceived(be);
+				break;
+
+			// Redraw the graph because the function table's selected values have changed.
+			// The function table is handled (setting of array of selected functions
+			// and table redraw) by the table selection listener or mouse listener.
+			case PIEvent.CHANGED_FUNCTION_TABLE:
+				switch(drawMode)
+				{
+					case Defines.FUNCTIONS_THREADS:
+					case Defines.FUNCTIONS_THREADS_BINARIES:
+					case Defines.FUNCTIONS_BINARIES:
+					case Defines.FUNCTIONS_BINARIES_THREADS:
+					{
+						this.functionTable.piEventReceived(be);
+						break;
+					}
+					case Defines.THREADS_FUNCTIONS_BINARIES:
+					{
+						this.threadTable.piEventReceived(be);
+						break;
+					}
+					case Defines.BINARIES_FUNCTIONS_THREADS:
+					{
+						this.binaryTable.piEventReceived(be);
+						break;
+					}
+					case Defines.THREADS:
+					case Defines.THREADS_BINARIES:
+					case Defines.THREADS_BINARIES_FUNCTIONS:
+					case Defines.THREADS_FUNCTIONS:
+					case Defines.BINARIES:
+					case Defines.BINARIES_THREADS:
+					case Defines.BINARIES_THREADS_FUNCTIONS:
+					case Defines.BINARIES_FUNCTIONS:
+					case Defines.FUNCTIONS:
+					default:
+						break;
+				}
+
+				this.vPanel.refreshCumulativeThreadTable();
+				this.repaint();
+				this.vPanel.piEventReceived(be);
+				break;
+
+			case PIEvent.MOUSE_PRESSED:
+				switch (drawMode) {
+					case Defines.THREADS:
+					{
+						break;
+					}
+					case Defines.BINARIES:
+					{
+						break;
+					}
+					case Defines.FUNCTIONS:
+					{
+						break;
+					}
+					default:
+					{
+						break;
+					}
+				}
+			    this.parentComponent.setActive(this);
+				break;
+				
+			default:
+				break;
+		}
+	}
+	
+	public void actionPerformed(ActionEvent ae)
+	{
+	}
+	
+	public void action(String actionString)
+	{
+	    System.out.println(Messages.getString("GppTraceGraph.actionString")+actionString);  //$NON-NLS-1$
+	    
+	    if (actionString.equals("resetToCurrentMode")) //$NON-NLS-1$
+	    {
+	        if (drawMode == Defines.THREADS_FUNCTIONS)
+	            this.setDrawMode(Defines.THREADS);
+	        else if (drawMode == Defines.BINARIES_FUNCTIONS)
+	            this.setDrawMode(Defines.BINARIES);
+	        else
+	            System.out.println(Messages.getString("GppTraceGraph.drawMode") + drawMode); //should not print this ever  //$NON-NLS-1$
+	    }
+	    else
+	    {
+			switch (drawMode)
+			{
+				case Defines.THREADS:
+				case Defines.THREADS_FUNCTIONS:
+				case Defines.THREADS_FUNCTIONS_BINARIES:
+				case Defines.THREADS_BINARIES:
+				case Defines.THREADS_BINARIES_FUNCTIONS:
+			    {
+					this.threadTable.action(actionString);
+			        break;
+			    }
+				case Defines.BINARIES:
+				case Defines.BINARIES_THREADS:
+				case Defines.BINARIES_THREADS_FUNCTIONS:
+				case Defines.BINARIES_FUNCTIONS:
+				case Defines.BINARIES_FUNCTIONS_THREADS:
+				{
+					this.binaryTable.action(actionString);
+					break;
+				}
+				case Defines.FUNCTIONS:
+				case Defines.FUNCTIONS_THREADS:
+				case Defines.FUNCTIONS_THREADS_BINARIES:
+				case Defines.FUNCTIONS_BINARIES:
+				case Defines.FUNCTIONS_BINARIES_THREADS:
+				{
+					this.functionTable.action(actionString);
+					break;
+				}
+			}
+	    }
+	}
+	
+	public void focusGained(FocusEvent fe)
+	{
+	}
+
+	public void focusLost(FocusEvent fe)
+	{
+	}
+
+	public void mouseDragged(MouseEvent me) {
+	}
+
+	public void mouseEntered(MouseEvent me) {
+	}
+
+	public void mouseExited(MouseEvent me) {
+	}
+
+	public void mouseHover(MouseEvent me) {
+	}
+
+	public void mousePressed(MouseEvent me) {
+	}
+
+	public void mouseReleased(MouseEvent me) {
+	}
+
+	public void mouseDoubleClicked(MouseEvent me)
+	{
+	    Object[] result = this.getProfiledGenericUnderMouse(me);
+		if ((result == null)) 
+		{
+			return;
+		}
+		
+		ProfiledGeneric pg = (ProfiledGeneric)result[0];
+		GenericTable gtu = null;
+
+		switch (drawMode)
+		{
+			case Defines.THREADS:
+			case Defines.BINARIES_THREADS:
+			case Defines.FUNCTIONS_THREADS:
+			case Defines.BINARIES_FUNCTIONS_THREADS:
+			case Defines.FUNCTIONS_BINARIES_THREADS:
+			{
+			    gtu = this.threadTable;
+			    break;
+			}
+			case Defines.BINARIES:
+			case Defines.THREADS_BINARIES:
+			case Defines.THREADS_FUNCTIONS_BINARIES:
+			case Defines.FUNCTIONS_BINARIES:
+			case Defines.FUNCTIONS_THREADS_BINARIES:
+			{
+			    gtu = this.binaryTable;
+				break;
+			}
+			case Defines.FUNCTIONS:
+			case Defines.THREADS_FUNCTIONS:
+			case Defines.BINARIES_FUNCTIONS:
+			case Defines.THREADS_BINARIES_FUNCTIONS:
+			case Defines.BINARIES_THREADS_FUNCTIONS:
+			{
+			    gtu = this.functionTable;
+			    break;
+			}
+			default:
+				break;
+		}
+
+		if (pg != null)
+		{
+			if (gtu.getIndex(pg) == null)
+				return;
+			int[] index = new int[1];
+			index[0] = gtu.getIndex(pg).intValue();
+			gtu.setSelectedIndicesXOR(index);
+		}
+	}
+
+	private Object[] getProfiledGenericUnderMouse(MouseEvent me)
+	{		
+		Object[] result = new Object[2];
+		double x = me.x * this.getScale();
+		double y = me.y;
+		
+		y = y * 100 / (this.getVisualSize().height - GppTraceGraph.xLegendHeight);
+		y = 100 - y;
+		if (y <= 0)
+			return null;
+		
+		// mouse event may return out of range X, that may 
+		// crash when we use it to index data array
+		x = x >= 0 ? x : 0;
+		
+		if (x > PIPageEditor.currentPageEditor().getMaxEndTime() * 1000)
+			return null;
+
+		if (me.x >= (int)(this.getSize().width)) {
+			x = (this.getSize().width - 1) * this.getScale();
+		}
+		
+		GppTrace gppTrace = (GppTrace) (this.getTrace());
+
+		Enumeration<ProfiledGeneric> enumer = null;
+		switch (drawMode)
+		{
+			case Defines.THREADS:
+			case Defines.BINARIES_THREADS:
+			case Defines.FUNCTIONS_THREADS:
+			case Defines.BINARIES_FUNCTIONS_THREADS:
+			case Defines.FUNCTIONS_BINARIES_THREADS:
+			{
+				enumer = gppTrace.getSortedThreadsElements();
+			    break;
+			}
+			case Defines.BINARIES:
+			case Defines.THREADS_BINARIES:
+			case Defines.THREADS_FUNCTIONS_BINARIES:
+			case Defines.FUNCTIONS_BINARIES:
+			case Defines.FUNCTIONS_THREADS_BINARIES:
+			{
+				enumer = gppTrace.getSortedBinariesElements();
+				break;
+			}
+			case Defines.FUNCTIONS:
+			case Defines.THREADS_FUNCTIONS:
+			case Defines.BINARIES_FUNCTIONS:
+			case Defines.THREADS_BINARIES_FUNCTIONS:
+			case Defines.BINARIES_THREADS_FUNCTIONS:
+			{
+		        enumer = gppTrace.getSortedFunctionsElements();
+			    break;
+			}
+			default:
+				break;
+		}
+
+		if (enumer == null)
+			return null;
+
+		Vector<ProfiledGeneric> activeThreads = new Vector<ProfiledGeneric>();
+		while(enumer.hasMoreElements())
+		{
+			ProfiledGeneric pg = (ProfiledGeneric)enumer.nextElement();
+			if (pg.isEnabled(this.graphIndex))		
+			{		
+				activeThreads.add(pg);
+			}
+		}
+		
+		int cumPrev = 0;
+		int cumNext = 0;
+		
+		int topPrev = 0;
+		int topNext = 0;
+
+		double cumDiff = 0;
+		double topDiff = 0;
+		
+		ProfiledGeneric currentProfiled = null;
+		
+		enumer = activeThreads.elements();
+		if (enumer.hasMoreElements())
+		    currentProfiled = enumer.nextElement();
+		
+		int samplingInterval = (Integer) NpiInstanceRepository.getInstance().activeUidGetPersistState("com.nokia.carbide.cpp.pi.address.samplingInterval"); //$NON-NLS-1$
+		int granularityValue = gppTrace.samples.size() > GppTraceGraph.granularityValue ? GppTraceGraph.granularityValue : gppTrace.samples.size();  
+
+		while (true)
+		{
+			if (currentProfiled != null)
+			{
+				int[] cum = currentProfiled.getCumulativeList(graphIndex);
+				int[] val = currentProfiled.getActivityList();
+				if (cum == null || val == null)
+					return null;
+				
+				int current = ((int)(x / samplingInterval)) / granularityValue;
+				
+				if ((current >= cum.length) || (current + 1 >= cum.length)) 
+					return null;
+					
+				cumPrev = cum[current];	
+				cumNext = cum[current + 1];
+
+				topPrev = val[current];
+				topNext = val[current + 1];
+
+				cumDiff = (cumNext - cumPrev) * ((double)((x / samplingInterval) % granularityValue) / (granularityValue * 1d));
+				topDiff = (topNext - topPrev) * ((double)((x / samplingInterval) % granularityValue) / (granularityValue * 1d));
+			}
+			else
+			{
+				if (y >= cumPrev + topPrev + topDiff + cumDiff) 
+				{
+				    currentProfiled = null;
+					break;
+				}
+				else
+				{
+					break;
+				}
+			}
+			
+			if (y >= cumPrev + cumDiff && y < cumPrev + topPrev + topDiff + cumDiff ) 
+			{
+				break;
+			}
+			else
+			{
+				if (enumer.hasMoreElements())
+				{
+				    currentProfiled = (ProfiledGeneric)enumer.nextElement();
+				}
+				else
+				{
+				    currentProfiled = null;
+				}
+			}
+		}
+		
+		if (currentProfiled != null)
+		{
+			String loadString = "" + (topPrev + topDiff); //$NON-NLS-1$
+			int index = loadString.indexOf('.');
+			
+			if (index > 0 && ((index + 2) < loadString.length()))
+				loadString = loadString.substring(0, index + 2); 
+			
+			result[0] = currentProfiled;
+			result[1] = loadString;				
+		}
+		else
+		{
+			String totalString = "" + (100 - (cumPrev + topPrev + topDiff + cumDiff)); //$NON-NLS-1$
+			int index = totalString.indexOf('.');
+			
+			if (index > 0 && ((index + 2) < totalString.length()))
+				totalString = totalString.substring(0, index + 2);
+
+			result[0] = null;
+			result[1] = totalString;
+		}
+		return result;
+	}
+
+	public void mouseMoved(MouseEvent me)
+	{
+		double x = me.x * this.getScale();
+		double y = me.y;
+		
+		// mouse event may return out of range X, that may 
+		// crash when we use it to index data array
+		x = x >= 0 ? x : 0;
+		
+		if (   y >= this.getVisualSizeY() - GppTraceGraph.xLegendHeight
+			|| x >= PIPageEditor.currentPageEditor().getMaxEndTime() * 1000)
+		{
+			this.setToolTipText(null);
+			return;
+		}
+
+		if (   NpiInstanceRepository.getInstance() == null
+			|| NpiInstanceRepository.getInstance().activeUidGetPersistState("com.nokia.carbide.cpp.pi.address.samplingInterval") == null) //$NON-NLS-1$)
+			return;
+		
+		int samplingInterval = (Integer) NpiInstanceRepository.getInstance().activeUidGetPersistState("com.nokia.carbide.cpp.pi.address.samplingInterval"); //$NON-NLS-1$
+
+		if (this.barMode == GppTraceGraph.BAR_MODE_ON) {
+			GppSample samp = (GppSample)((GenericSampledTrace)this.getTrace()).getSample(((int)(x + .0005))/samplingInterval);
+			switch (drawMode)
+			{
+				case Defines.THREADS:
+				case Defines.BINARIES_THREADS:
+				case Defines.FUNCTIONS_THREADS:
+				case Defines.BINARIES_FUNCTIONS_THREADS:
+				case Defines.FUNCTIONS_BINARIES_THREADS:
+				{
+					try {
+						this.setToolTipText(samp.sampleSynchTime+"ms @"+  //$NON-NLS-1$
+											Long.toHexString(samp.programCounter)+" "+  //$NON-NLS-1$
+											samp.thread.process.name+"::"+  //$NON-NLS-1$
+											samp.thread.threadName+"_"+  //$NON-NLS-1$
+											samp.thread.threadId);}
+					catch (NullPointerException e2)
+					{
+						this.setToolTipText(Messages.getString("GppTraceGraph.cannotResolveThreadName"));  //$NON-NLS-1$
+					}
+					break;
+				}
+				case Defines.BINARIES:
+				case Defines.THREADS_BINARIES:
+				case Defines.THREADS_FUNCTIONS_BINARIES:
+				case Defines.FUNCTIONS_BINARIES:
+				case Defines.FUNCTIONS_THREADS_BINARIES:
+				{
+					try {
+						if (samp.currentFunctionSym.functionBinary.binaryName.endsWith(Messages.getString("GppTraceGraph.NotFound")))  //$NON-NLS-1$
+							throw new NullPointerException();
+						this.setToolTipText(samp.sampleSynchTime+"ms @"+  //$NON-NLS-1$
+											Long.toHexString(samp.programCounter)+" "+  //$NON-NLS-1$
+											samp.currentFunctionSym.functionBinary.binaryName);
+					} catch (NullPointerException e)
+					{
+						try {
+							this.setToolTipText(samp.sampleSynchTime+"ms @"+  //$NON-NLS-1$
+												Long.toHexString(samp.programCounter)+" "+  //$NON-NLS-1$
+												samp.currentFunctionItt.functionBinary.binaryName);}
+						catch (NullPointerException e2)
+						{
+							this.setToolTipText(Messages.getString("GppTraceGraph.cannotResolveBinaryName"));  //$NON-NLS-1$
+						}
+					}
+					break;
+				}
+				case Defines.FUNCTIONS:
+				case Defines.THREADS_FUNCTIONS:
+				case Defines.BINARIES_FUNCTIONS:
+				case Defines.THREADS_BINARIES_FUNCTIONS:
+				case Defines.BINARIES_THREADS_FUNCTIONS:
+				{
+					try {
+						if (samp.currentFunctionSym.functionBinary.binaryName.endsWith(Messages.getString("GppTraceGraph.notFound")))  //$NON-NLS-1$
+							throw new NullPointerException();
+						
+						this.setToolTipText(samp.sampleSynchTime+"ms @"+  //$NON-NLS-1$
+											Long.toHexString(samp.programCounter)+" "+  //$NON-NLS-1$
+											samp.currentFunctionSym.functionName);}
+					catch (NullPointerException e)
+					{
+						try{this.setToolTipText(samp.sampleSynchTime+"ms @"+  //$NON-NLS-1$
+												Long.toHexString(samp.programCounter)+" "+  //$NON-NLS-1$
+												samp.currentFunctionItt.functionName);}
+						catch (NullPointerException e2)
+						{
+							this.setToolTipText(Messages.getString("GppTraceGraph.cannotResolveFunctionName"));  //$NON-NLS-1$
+						}
+					}
+					break;
+				}
+				default:
+					return;
+			}
+
+			return;  // return for barMode == GppTraceGraph.BAR_MODE_ON
+		}
+
+		// barMode == GppTraceGraph.BAR_MODE_OFF
+
+    	Object[] result = this.getProfiledGenericUnderMouse(me);
+		if (result == null)
+		{
+			this.setToolTipText(null);
+			return;
+		}
+		
+		if (me.x >= (int)(this.getSize().width)) {
+			x = (this.getSize().width - 1) * this.getScale();
+		}
+		
+		ProfiledGeneric pg = null;
+		switch (drawMode)
+		{
+			case Defines.THREADS:
+			case Defines.BINARIES_THREADS:
+			case Defines.FUNCTIONS_THREADS:
+			case Defines.BINARIES_FUNCTIONS_THREADS:
+			case Defines.FUNCTIONS_BINARIES_THREADS:
+			{
+			    pg = (ProfiledThread)result[0];
+			    break;
+			}
+			case Defines.BINARIES:
+			case Defines.THREADS_BINARIES:
+			case Defines.THREADS_FUNCTIONS_BINARIES:
+			case Defines.FUNCTIONS_BINARIES:
+			case Defines.FUNCTIONS_THREADS_BINARIES:
+			{
+			    pg = (ProfiledBinary)result[0];
+				break;
+			}
+			case Defines.FUNCTIONS:
+			case Defines.THREADS_FUNCTIONS:
+			case Defines.BINARIES_FUNCTIONS:
+			case Defines.THREADS_BINARIES_FUNCTIONS:
+			case Defines.BINARIES_THREADS_FUNCTIONS:
+			{
+			    pg = (ProfiledFunction)result[0];
+			    break;
+			}
+			default:
+				break;
+		}
+
+		String string = (String)result[1];
+		if (pg == null)
+		{
+			switch (drawMode)
+			{
+				case Defines.THREADS:
+				case Defines.BINARIES_THREADS:
+				case Defines.FUNCTIONS_THREADS:
+				case Defines.BINARIES_FUNCTIONS_THREADS:
+				case Defines.FUNCTIONS_BINARIES_THREADS:
+				{
+				    this.setToolTipText(string + "% " + Messages.getString("GppTraceGraph.unknownOrExcludedThreads"));  //$NON-NLS-1$ //$NON-NLS-2$
+				    break;
+				}
+				case Defines.BINARIES:
+				case Defines.THREADS_BINARIES:
+				case Defines.THREADS_FUNCTIONS_BINARIES:
+				case Defines.FUNCTIONS_BINARIES:
+				case Defines.FUNCTIONS_THREADS_BINARIES:
+				{
+				    this.setToolTipText(string + "% " + Messages.getString("GppTraceGraph.unknownOrExcludedBinaries"));  //$NON-NLS-1$ //$NON-NLS-2$
+					break;
+				}
+				case Defines.FUNCTIONS:
+				case Defines.THREADS_FUNCTIONS:
+				case Defines.BINARIES_FUNCTIONS:
+				case Defines.THREADS_BINARIES_FUNCTIONS:
+				case Defines.BINARIES_THREADS_FUNCTIONS:
+				{
+				    this.setToolTipText(string + "% " + Messages.getString("GppTraceGraph.unknownOrExcludedFunctions"));  //$NON-NLS-1$ //$NON-NLS-2$
+				    break;
+				}
+				default:
+					break;
+			}
+		}
+		else
+		{
+			this.setToolTipText(string + "% " + pg.getNameString());  //$NON-NLS-1$
+		}
+	}
+	
+	public GenericTable getTableUtils()
+	{
+		switch (drawMode)
+		{
+			case Defines.THREADS:
+			case Defines.BINARIES_THREADS:
+			case Defines.FUNCTIONS_THREADS:
+			case Defines.BINARIES_FUNCTIONS_THREADS:
+			case Defines.FUNCTIONS_BINARIES_THREADS:
+			{
+			    return this.threadTable;
+			}
+			case Defines.BINARIES:
+			case Defines.THREADS_BINARIES:
+			case Defines.THREADS_FUNCTIONS_BINARIES:
+			case Defines.FUNCTIONS_BINARIES:
+			case Defines.FUNCTIONS_THREADS_BINARIES:
+			{
+			    return this.binaryTable;
+			}
+			case Defines.FUNCTIONS:
+			case Defines.THREADS_FUNCTIONS:
+			case Defines.BINARIES_FUNCTIONS:
+			case Defines.THREADS_BINARIES_FUNCTIONS:
+			case Defines.BINARIES_THREADS_FUNCTIONS:
+			{
+			    return this.functionTable;
+			}
+			default:
+				break;
+		}
+
+		System.out.println(Messages.getString("GppTraceGraph.debugDrawMode") + drawMode);  //$NON-NLS-1$
+	    return null;
+	}
+	
+	public GppVisualiserPanel getVisualiserPanel()
+	{
+		return this.vPanel;
+	}
+	
+	public AddrThreadTable  getThreadTable() {
+		return this.threadTable;
+	}
+	
+	public AddrBinaryTable getBinaryTable() {
+		return this.binaryTable;
+	}
+	
+	public AddrFunctionTable getFunctionTable() {
+		return this.functionTable;
+	}
+
+	public void setThreadTableViewer(CheckboxTableViewer tableViewer) {
+		this.threadTable.setTableViewer(tableViewer);
+	}
+	
+	public void setBinaryTableViewer(CheckboxTableViewer tableViewer) {
+		this.binaryTable.setTableViewer(tableViewer);;
+	}
+	
+	public void setFunctionTableViewer(CheckboxTableViewer tableViewer) {
+		this.functionTable.setTableViewer(tableViewer);
+	}
+
+	public void paint(Panel panel, Graphics graphics)
+	{
+		this.setSize(panel.getClientArea().width, panel.getClientArea().height);
+		this.vPanel.paintComponent(panel, graphics);
+	}
+
+	public void paintLeftLegend(FigureCanvas figureCanvas, GC gc)
+	{
+		GC localGC = gc;
+		
+		if (gc == null)
+			gc = new GC(PIPageEditor.currentPageEditor().getSite().getShell());
+
+		Rectangle rect = ((GraphComposite) figureCanvas.getParent()).figureCanvas.getClientArea();
+		
+		int visY = rect.height;
+		
+		float visYfloat = visY - GppTraceGraph.xLegendHeight;
+		
+		if (visYfloat < 0f)
+			visYfloat = 0f;
+		
+		gc.setForeground(ColorPalette.getColor(new RGB(100, 100, 100)));
+		gc.setBackground(ColorPalette.getColor(new RGB(255, 255, 255)));
+		
+		// write each next number if there is space
+		// float values will be slightly smaller than the actual result
+		// and they will be incremented by one, since rounding to int
+		// discards the remaining decimals
+		int percent = 100;
+		int previousBottom = 0;		// bottom of the previous legend drawn
+		for (float y = 0f; percent >= 0; y += visYfloat * 10000f / 100001f, percent -= 10)
+		{
+			String legend = "" + percent + "%"; //$NON-NLS-1$ //$NON-NLS-2$
+			Point extent = gc.stringExtent(legend);
+			
+			gc.drawLine(GenericTraceGraph.yLegendWidth - 3, (int)y + 1, GenericTraceGraph.yLegendWidth, (int)y + 1);
+
+			if ((int)y >= previousBottom)
+			{
+				gc.drawString(legend, GenericTraceGraph.yLegendWidth - extent.x - 4, (int)y);
+				previousBottom = (int)y + extent.y;
+			}
+		}
+		
+		if (localGC == null) {
+			gc.dispose();
+			figureCanvas.redraw();
+		}
+	}
+	
+	public void repaint()
+	{
+		this.parentComponent.repaintComponent();
+	}
+	
+	public void drawBarsGpp(Vector<ProfiledGeneric> profiledGenerics, Graphics graphics, Object[] selection)
+	{
+		if (   this.updateCumulativeThreadTableIsNeeded
+			|| this.barGraphData == null)
+		{
+			this.updateBarGraphData(profiledGenerics);
+		}
+		
+		this.updateIfNeeded(profiledGenerics);
+		
+		Enumeration<BarGraphData> barEnum = this.barGraphData.elements();
+
+		int drawX = -1;
+		int lastDrawX = -10;
+		double scale = this.getScale();
+		int y = this.getVisualSizeY() - 51;
+		org.eclipse.draw2d.geometry.Rectangle visibleArea = this.getVisibleArea(graphics);
+
+		while(barEnum.hasMoreElements())
+		{
+			BarGraphData bgd = barEnum.nextElement();
+			drawX = (int)(((double)bgd.x) / scale);
+			
+			if (   drawX >= visibleArea.x
+				&& drawX < visibleArea.x + visibleArea.width )
+			{
+				if (debug)
+					System.out.println(Messages.getString("GppTraceGraph.draw") + drawX + " " + scale + " " + bgd.x);    //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+				if (drawX != lastDrawX)
+				{
+					graphics.setForegroundColor(bgd.color);
+					graphics.drawLine(drawX, 0, drawX, y);
+					lastDrawX = drawX;
+				}
+			}
+		}
+	}
+
+	public void updateBarGraphData(Vector profiledGenerics)
+	{
+		if (this.barGraphData == null)
+			this.barGraphData = new Vector<BarGraphData>();
+		this.barGraphData.clear();
+
+		int x = 0;
+		
+		// find the first enabled profiled generic
+		int firstEnabled;
+		for (firstEnabled = 0; firstEnabled < profiledGenerics.size(); firstEnabled++)
+			if (((ProfiledGeneric)profiledGenerics.get(firstEnabled)).isEnabled(this.graphIndex))
+				break;
+		
+		// return if there are no enabled profiled generics
+		if (firstEnabled == profiledGenerics.size())
+			return;
+		
+		int samplingInterval = (Integer) NpiInstanceRepository.getInstance().activeUidGetPersistState("com.nokia.carbide.cpp.pi.address.samplingInterval"); //$NON-NLS-1$
+		Enumeration samples = ((GenericSampledTrace)this.getTrace()).getSamples();
+		while (samples.hasMoreElements())
+		{
+			GppSample gs = (GppSample)samples.nextElement();
+			
+			// for each of the tens of thousands of samples, loop through each of the
+			// perhaps thousands of functions, hundreds of binaries, or tens of threads
+			for (int i = firstEnabled; i < profiledGenerics.size(); i++)
+			{
+				// find the next enabled profiled generic, if any
+				while (   (i < profiledGenerics.size()
+					   && !((ProfiledGeneric)profiledGenerics.get(i)).isEnabled(this.graphIndex)))
+					i++;
+				if (i >= profiledGenerics.size())
+					break;
+
+				ProfiledGeneric pg = (ProfiledGeneric)profiledGenerics.get(i);
+
+				if (   ((pg instanceof ProfiledThread)   && (pg.getIndex() == gs.threadIndex))
+				    || ((pg instanceof ProfiledBinary)   && (pg.getIndex() == gs.binaryIndex))
+				    || ((pg instanceof ProfiledFunction) && (pg.getIndex() == gs.functionIndex))) {
+					BarGraphData bgd = new BarGraphData();
+					bgd.color = pg.getColor();
+					bgd.x = x;
+					this.barGraphData.add(bgd);
+					break;
+				}
+			}
+			x += samplingInterval;
+		}
+	}	
+
+	public void refreshDataFromTrace()
+	{
+		refreshDataFromTrace((GppTrace)this.getTrace());
+
+	    if (this.vPanel != null)
+		{
+			this.vPanel.refreshCumulativeThreadTable();
+		}
+	}
+
+	public static void refreshDataFromTrace(GppTrace gppTrace)
+	{
+		Enumeration enumer = gppTrace.getSamples();
+		
+		int granularityValue = gppTrace.samples.size() > GppTraceGraph.granularityValue ? GppTraceGraph.granularityValue : gppTrace.samples.size();  
+
+		Hashtable<String,ProfiledGeneric> profiledThreads   = new Hashtable<String,ProfiledGeneric>();
+		Hashtable<String,ProfiledGeneric> profiledBinaries  = new Hashtable<String,ProfiledGeneric>();
+		Hashtable<String,ProfiledGeneric> profiledFunctions = new Hashtable<String,ProfiledGeneric>();
+		
+		Hashtable<ProfiledGeneric,Integer> threadPercentages   = new Hashtable<ProfiledGeneric,Integer>();
+		Hashtable<ProfiledGeneric,Integer> binaryPercentages   = new Hashtable<ProfiledGeneric,Integer>();
+		Hashtable<ProfiledGeneric,Integer> functionPercentages = new Hashtable<ProfiledGeneric,Integer>();
+		
+		int threadCount = 0;
+		int binaryCount = 0;
+		int functionCount = 0;
+		int count = 0;
+		int timeStamp = 0;
+		int stepValue = granularityValue;
+		char threadSymbol = 'A';
+		int samplingInterval = (Integer) NpiInstanceRepository.getInstance().activeUidGetPersistState("com.nokia.carbide.cpp.pi.address.samplingInterval"); //$NON-NLS-1$
+
+		Vector<ProfiledGeneric> sortedProfiledThreads   = gppTrace.getSortedThreads();
+		Vector<ProfiledGeneric> sortedProfiledBinaries  = gppTrace.getSortedBinaries();
+		Vector<ProfiledGeneric> sortedProfiledFunctions = gppTrace.getSortedFunctions();
+
+		Vector<ProfiledGeneric> unsortedProfiledThreads   = gppTrace.getIndexedThreads();
+		Vector<ProfiledGeneric> unsortedProfiledBinaries  = gppTrace.getIndexedBinaries();
+		Vector<ProfiledGeneric> unsortedProfiledFunctions = gppTrace.getIndexedFunctions();
+		
+		// reset these list so we can call refreshDataFromTrace mulitple times (e.g. import) while keeping size consistent
+		sortedProfiledThreads.clear();
+		sortedProfiledBinaries.clear();
+		sortedProfiledFunctions.clear();
+
+		unsortedProfiledThreads.clear();
+		unsortedProfiledBinaries.clear();
+		unsortedProfiledFunctions.clear();
+
+		boolean exit = false;
+		while (exit == false)
+		{
+			exit = !enumer.hasMoreElements();
+			if (exit == true) 
+			{
+				// for the final samples, modify the step value
+				// so that they will also be included
+				// now there are no new samples, so proceed directly to
+				// adding the final values to the percent list
+				stepValue = count;
+			}
+			else
+			{
+				count++;
+				
+				// there is at least one new sample in the enumeration, so resolve it 
+				GppSample sample = (GppSample)enumer.nextElement();
+				String threadName   = sample.thread.process.name + "::" + sample.thread.threadName + "_" + sample.thread.threadId;   //$NON-NLS-1$ //$NON-NLS-2$
+				String binaryName   = getBinaryName(sample);
+				String functionName = getFunctionName(sample);
+
+				ProfiledThread   pThread = null;
+				ProfiledBinary   pBinary = null;
+				ProfiledFunction pFunction = null;
+				
+				// handle new thread names
+				if (profiledThreads.containsKey(threadName))
+				{
+					pThread = (ProfiledThread)profiledThreads.get(threadName);
+					if (pThread.getThreadId() != sample.thread.threadId.intValue())
+					{
+						// this was not the same thread, even though the
+						// name was the same
+						pThread = null;
+					}
+				}
+			
+				if (pThread == null)
+				{
+					pThread = new ProfiledThread();
+					
+					pThread.setIndex(threadCount++);
+					pThread.setNameValues(threadSymbol++, threadName);
+					pThread.setColor(gppTrace.getThreadColorPalette().getColor(threadName));
+					
+					pThread.setThreadId(sample.thread.threadId.intValue());
+					
+					pThread.setActivityMarkCount((gppTrace.samples.size() + granularityValue) / granularityValue + 1);
+					for (int i = 0; i < timeStamp + stepValue * samplingInterval; i += stepValue * samplingInterval)
+					{
+						pThread.zeroActivityMarkValues(i);
+					}
+					profiledThreads.put(threadName, pThread);
+					sortedProfiledThreads.add((ProfiledGeneric)pThread);			
+					unsortedProfiledThreads.add((ProfiledGeneric)pThread);			
+				}
+				
+				pThread.incTotalSampleCount();
+				sample.threadIndex = pThread.getIndex();
+
+				if (threadPercentages.containsKey(pThread))
+				{
+					Integer value = (Integer)threadPercentages.get(pThread);
+					value = new Integer(value.intValue()+1);
+					threadPercentages.remove(pThread);
+					threadPercentages.put(pThread, value);
+				}
+				else
+				{
+					threadPercentages.put(pThread, new Integer(1));
+				}
+				
+				// handle new binary names
+				if (profiledBinaries.containsKey(binaryName))
+				{
+					pBinary = (ProfiledBinary)profiledBinaries.get(binaryName);
+				}
+			
+				if (pBinary == null)
+				{
+					pBinary = new ProfiledBinary();
+
+					pBinary.setIndex(binaryCount++);
+					pBinary.setNameString(binaryName);
+					pBinary.setColor(gppTrace.getBinaryColorPalette().getColor(binaryName));
+					
+					pBinary.setActivityMarkCount((gppTrace.samples.size() + granularityValue) / granularityValue + 1);
+					for (int i = 0; i < timeStamp + stepValue * samplingInterval; i += stepValue * samplingInterval)
+					{
+						pBinary.zeroActivityMarkValues(i);
+					}
+					profiledBinaries.put(binaryName,pBinary);
+					sortedProfiledBinaries.add((ProfiledGeneric)pBinary);			
+					unsortedProfiledBinaries.add((ProfiledGeneric)pBinary);			
+				}
+				
+				pBinary.incTotalSampleCount();
+				sample.binaryIndex = pBinary.getIndex();
+
+				if (binaryPercentages.containsKey(pBinary))
+				{
+					Integer value = (Integer)binaryPercentages.get(pBinary);
+					value = new Integer(value.intValue()+1);
+					binaryPercentages.remove(pBinary);
+					binaryPercentages.put(pBinary,value);
+				}
+				else
+				{
+					binaryPercentages.put(pBinary, new Integer(1));
+				}														
+				
+				// handle new function names
+				if (profiledFunctions.containsKey(functionName))
+				{
+					pFunction = (ProfiledFunction)profiledFunctions.get(functionName);
+				}
+			
+				if (pFunction == null)
+				{
+					pFunction = new ProfiledFunction();
+
+					pFunction.setIndex(functionCount++);
+					pFunction.setNameString(functionName);
+					pFunction.setFunctionAddress(getFunctionAddress(sample));
+					pFunction.setFunctionBinaryName(binaryName);
+					pFunction.setColor(gppTrace.getFunctionColorPalette().getColor(functionName));
+					
+					pFunction.setActivityMarkCount((gppTrace.samples.size() + granularityValue) / granularityValue + 1);
+					for (int i = 0; i < timeStamp + stepValue * samplingInterval; i += stepValue * samplingInterval)
+					{
+						pFunction.zeroActivityMarkValues(i);
+					}
+					profiledFunctions.put(functionName,pFunction);
+					sortedProfiledFunctions.add((ProfiledGeneric)pFunction);			
+					unsortedProfiledFunctions.add((ProfiledGeneric)pFunction);			
+				}
+
+				pFunction.incTotalSampleCount();
+				sample.functionIndex = pFunction.getIndex();
+
+				if (functionPercentages.containsKey(pFunction))
+				{
+					Integer value = (Integer)functionPercentages.get(pFunction);
+					value = new Integer(value.intValue()+1);
+					functionPercentages.remove(pFunction);
+					functionPercentages.put(pFunction,value);
+				}
+				else
+				{
+					functionPercentages.put(pFunction, new Integer(1));
+				}														
+			}
+			
+			// for each stepValue (or final values) samples
+			// add the data to the profiled threads, binaries, functions
+			if (stepValue != 0 && count == stepValue)
+			{
+				Vector<ProfiledGeneric> tmpVector;
+				
+				tmpVector = new Vector<ProfiledGeneric>(profiledThreads.values());
+				Enumeration<ProfiledGeneric> ptEnum = tmpVector.elements();
+				while (ptEnum.hasMoreElements())
+				{
+					ProfiledThread updatePt = (ProfiledThread)ptEnum.nextElement();
+					if (threadPercentages.containsKey(updatePt))
+					{
+						int samples = ((Integer)(threadPercentages.get(updatePt))).intValue();
+						int finalPerc = (samples * 100) / stepValue;
+						updatePt.addActivityMarkValues(timeStamp + stepValue * samplingInterval, finalPerc, samples);
+					}
+					else
+					{
+						updatePt.zeroActivityMarkValues(timeStamp + stepValue * samplingInterval);
+					}					
+				}
+				
+				tmpVector = new Vector<ProfiledGeneric>(profiledBinaries.values());
+				Enumeration<ProfiledGeneric> pbEnum = tmpVector.elements();
+				while (pbEnum.hasMoreElements())
+				{
+					ProfiledBinary updatePb = (ProfiledBinary)pbEnum.nextElement();
+					if (binaryPercentages.containsKey(updatePb))
+					{
+						int samples = ((Integer)(binaryPercentages.get(updatePb))).intValue();
+						int finalPerc = (samples * 100) / stepValue;
+						updatePb.addActivityMarkValues(timeStamp + stepValue * samplingInterval, finalPerc, samples);
+					}
+					else
+					{
+						updatePb.zeroActivityMarkValues(timeStamp + stepValue * samplingInterval);
+					}					
+				}
+				
+				tmpVector = new Vector<ProfiledGeneric>(profiledFunctions.values());
+				Enumeration<ProfiledGeneric> pfEnum = tmpVector.elements();
+				while (pfEnum.hasMoreElements())
+				{
+					ProfiledFunction updatePf = (ProfiledFunction)pfEnum.nextElement();
+					if (functionPercentages.containsKey(updatePf))
+					{
+						int samples = ((Integer)(functionPercentages.get(updatePf))).intValue();
+						int finalPerc = (samples * 100) / stepValue;
+						updatePf.addActivityMarkValues(timeStamp + stepValue * samplingInterval, finalPerc, samples);
+					}
+					else
+					{
+						updatePf.zeroActivityMarkValues(timeStamp + stepValue * samplingInterval);
+					}					
+				}
+
+				threadPercentages.clear();
+				binaryPercentages.clear();
+				functionPercentages.clear();
+				count = 0;
+				timeStamp += stepValue * samplingInterval;
+			}
+		}
+		
+		// if there is no end point for a profiled element with samples, set the end to the last sample in the trace 
+		for (Enumeration<ProfiledGeneric> e = profiledThreads.elements(); e.hasMoreElements(); ) {
+			ProfiledGeneric pg = e.nextElement();
+			
+			if (pg.getRealLastSample() == -1 && pg.getTotalSampleCount() != 0)
+				pg.setLastSample(gppTrace.samples.size() * samplingInterval);
+		}
+
+		for (Enumeration<ProfiledGeneric> e = profiledBinaries.elements(); e.hasMoreElements(); ) {
+			ProfiledGeneric pg = e.nextElement();
+			
+			if (pg.getRealLastSample() == -1 && pg.getTotalSampleCount() != 0)
+				pg.setLastSample(gppTrace.samples.size() * samplingInterval);
+		}
+
+		for (Enumeration<ProfiledGeneric> e = profiledFunctions.elements(); e.hasMoreElements(); ) {
+			ProfiledGeneric pg = e.nextElement();
+			
+			if (pg.getRealLastSample() == -1 && pg.getTotalSampleCount() != 0)
+				pg.setLastSample(gppTrace.samples.size() * samplingInterval);
+		}
+
+		// sort the thread, binary, and function vectors by load
+		sortProfiledGenerics(profiledThreads, gppTrace);
+		sortProfiledGenerics(profiledBinaries, gppTrace);
+		sortProfiledGenerics(profiledFunctions, gppTrace);
+		
+		// the trace-level count arrays are initialized to 0
+		gppTrace.setThreadSampleCounts(new int[profiledThreads.size()]);
+		gppTrace.setBinarySampleCounts(new int[profiledBinaries.size()]);
+		gppTrace.setFunctionSampleCounts(new int[profiledFunctions.size()]);
+	}
+	
+	/*
+	 * Because a table to the left of a function table has changed, update
+	 * the function table.
+	 * If there is no table to the right of this one, redraw the graph based
+	 * on the changed data.
+	 */
+	public void refreshProfiledThreadData(int drawMode)
+	{
+		// Must have a table to its left
+	    if (   (drawMode != Defines.BINARIES_THREADS)
+	    	&& (drawMode != Defines.BINARIES_THREADS_FUNCTIONS)
+	    	&& (drawMode != Defines.BINARIES_FUNCTIONS_THREADS)
+	    	&& (drawMode != Defines.FUNCTIONS_THREADS)
+	    	&& (drawMode != Defines.FUNCTIONS_THREADS_BINARIES)
+	    	&& (drawMode != Defines.FUNCTIONS_BINARIES_THREADS)
+	    	)
+	    {
+	        System.out.println(Messages.getString("GppTraceGraph.wrongDrawMode"));  //$NON-NLS-1$
+	        return;
+	    }
+
+	    // boolean to use inside loops (should trust a compiler to optimize this out of the loop...)
+	    boolean basedOnBinaries = (drawMode == Defines.BINARIES_THREADS)
+	    					   || (drawMode == Defines.BINARIES_THREADS_FUNCTIONS)
+	    					   || (drawMode == Defines.FUNCTIONS_BINARIES_THREADS); 
+
+	    Hashtable<String,ProfiledThread> profiledThreads = new Hashtable<String,ProfiledThread>();
+		
+	    GenericSampledTrace trace = (GenericSampledTrace)this.getTrace();
+		int granularityValue = trace.samples.size() > GppTraceGraph.granularityValue ? GppTraceGraph.granularityValue : trace.samples.size();  
+		
+	    String[] selectedItems;
+		int[] selectedFunctionHashCodes = null;
+		int[] selectedBinaryHashCodes   = null;
+		int count = 0;
+		int timeStamp = 0;
+		int stepValue = granularityValue;
+		int samplingInterval = (Integer) NpiInstanceRepository.getInstance().activeUidGetPersistState("com.nokia.carbide.cpp.pi.address.samplingInterval"); //$NON-NLS-1$
+		boolean exit = false;
+		
+		Hashtable<ProfiledThread,Integer> percentages = new Hashtable<ProfiledThread,Integer>();
+		PIVisualSharedData shared = this.getSharedDataInstance();
+		
+	    if (basedOnBinaries)
+		{
+		    selectedItems = shared.GPP_SelectedBinaryNames;
+		    if (selectedItems == null) 
+	        {
+		        selectedItems = new String[0];
+	        }
+		    int[] tmpHashCodes = new int[selectedItems.length];
+		    for (int i = 0; i < selectedItems.length; i++)
+		    {
+		        String tmp = selectedItems[i];
+		        tmpHashCodes[i] = tmp.hashCode();
+		    }
+		    selectedBinaryHashCodes = tmpHashCodes;
+		}
+		else
+		{
+		    selectedItems = shared.GPP_SelectedFunctionNames;
+		    if (selectedItems == null) 
+	        {
+		        selectedItems = new String[0];
+	        }
+		    int[] tmpHashCodes = new int[selectedItems.length];
+		    for (int i = 0; i < selectedItems.length; i++)
+		    {
+		        String tmp = selectedItems[i];
+		        tmpHashCodes[i] = tmp.hashCode();
+		    }
+		    selectedFunctionHashCodes = tmpHashCodes;
+		}
+		
+		for (Enumeration enumer = trace.getSamples(); !exit;)
+		{
+		    exit = !enumer.hasMoreElements();
+			if (exit)
+			{
+				// for the final samples, modify the step value
+				// so that they will also be included
+				// now there are no new samples, so proceed directly to
+				// adding the final values to the percent list
+				stepValue = count;
+			}
+			else
+			{
+			    count++;
+			    int compareValue = 0;
+			    boolean match = false;
+			    GppSample sample = (GppSample)enumer.nextElement();
+			    if (basedOnBinaries)
+				{
+				    compareValue = getBinaryName(sample).hashCode();
+				    for (int i = 0; i < selectedBinaryHashCodes.length; i++)
+				    {
+				        if (compareValue == selectedBinaryHashCodes[i])
+				        {
+				            match = true;
+				            break;
+				        }
+				    }
+				}
+			    else
+			    {
+				    compareValue = getFunctionName(sample).hashCode();
+				    for (int i = 0; i < selectedFunctionHashCodes.length; i++)
+				    {
+				        if (compareValue == selectedFunctionHashCodes[i])
+				        {
+				            match = true;
+				            break;
+				        }
+				    }
+			    }
+			    
+			    if (match)
+			    {
+			        ProfiledThread pt = null;
+			        String name = sample.thread.threadName;
+					if (profiledThreads.containsKey(name))
+					{
+						pt = (ProfiledThread)profiledThreads.get(name);
+					}
+				
+					if (pt == null)
+					{
+						pt = new ProfiledThread();
+					
+						pt.setNameString(name);
+						pt.setColor(((GppTrace)this.getTrace()).getThreadColorPalette().getColor(name));
+						pt.setThreadId(sample.thread.threadId.intValue());
+						
+						pt.setActivityMarkCount((trace.samples.size() + granularityValue) / granularityValue + 1);
+						for (int i = 0; i < timeStamp + stepValue * samplingInterval; i += stepValue * samplingInterval)
+						{
+							pt.zeroActivityMarkValues(i);
+						}
+						pt.setEnabled(this.graphIndex, true);
+						profiledThreads.put(name, pt);
+					}
+	
+					if (percentages.containsKey(pt))
+					{
+						Integer value = (Integer)percentages.get(pt);
+						value = new Integer(value.intValue()+1);
+						percentages.remove(pt);
+						percentages.put(pt,value);
+					}
+					else
+					{
+						percentages.put(pt,new Integer(1));
+					}
+			    }
+			}
+
+			if (stepValue != 0 && count == stepValue)
+			{	
+				Vector<ProfiledGeneric> v = new Vector<ProfiledGeneric>(profiledThreads.values());
+				Enumeration<ProfiledGeneric> pfEnum = v.elements();
+				while (pfEnum.hasMoreElements())
+				{
+					ProfiledThread updatePt = (ProfiledThread)pfEnum.nextElement();
+					if (percentages.containsKey(updatePt))
+					{
+						int samples = ((Integer)(percentages.get(updatePt))).intValue();
+						int finalPerc = (samples * 100) / stepValue;
+						updatePt.addActivityMarkValues(timeStamp + stepValue * samplingInterval, finalPerc, samples);
+					}
+					else
+					{
+						updatePt.zeroActivityMarkValues(timeStamp + stepValue * samplingInterval);
+					}					
+				}
+				
+				percentages.clear();
+				count = 0;
+				timeStamp += stepValue * samplingInterval;
+			}
+		}
+
+		this.threadTable.getTable().deselectAll();
+		this.threadTable.updateProfiledAndItemData(true);
+		this.threadTable.getTable().redraw();
+
+		// if this is not the last table, set the selected names to set up
+		// the next table
+	    if (   (drawMode == Defines.BINARIES_THREADS_FUNCTIONS)
+	    	|| (drawMode == Defines.FUNCTIONS_THREADS_BINARIES))
+	    {
+	    	this.threadTable.setSelectedNames();
+	    }
+	    else
+	    {
+	    	// This may not be needed needed
+			shared.GPP_SelectedThreadNames = new String[0];
+	    }
+	}
+
+	/*
+	 * Because a table to the left of a binary table has changed, update
+	 * the binary table.
+	 * If there is no table to the right of this one, redraw the graph based
+	 * on the changed data.
+	 */
+	public void refreshProfiledBinaryData(int drawMode)
+	{
+		// Must have a table to its left
+	    if (   (drawMode != Defines.THREADS_BINARIES)
+	    	&& (drawMode != Defines.THREADS_BINARIES_FUNCTIONS)
+	    	&& (drawMode != Defines.THREADS_FUNCTIONS_BINARIES)
+	    	&& (drawMode != Defines.FUNCTIONS_BINARIES)
+	    	&& (drawMode != Defines.FUNCTIONS_BINARIES_THREADS)
+	    	&& (drawMode != Defines.FUNCTIONS_THREADS_BINARIES)
+	       )
+	    {
+	        System.out.println(Messages.getString("GppTraceGraph.wrongDrawMode"));  //$NON-NLS-1$
+	        return;
+	    }
+
+	    // boolean to use inside loops (never trust a compiler...)
+	    boolean basedOnThreads = (drawMode == Defines.THREADS_BINARIES)
+	    					  || (drawMode == Defines.THREADS_BINARIES_FUNCTIONS)
+	    					  || (drawMode == Defines.FUNCTIONS_THREADS_BINARIES); 
+
+	    Hashtable<String,ProfiledBinary> profiledBinaries = new Hashtable<String,ProfiledBinary>();
+		
+	    GenericSampledTrace trace = (GenericSampledTrace)this.getTrace();
+		int granularityValue = trace.samples.size() > GppTraceGraph.granularityValue ? GppTraceGraph.granularityValue : trace.samples.size();  
+
+		String[] selectedItems;
+		int[] selectedThreadIds = null;
+		int[] selectedFunctionHashCodes = null;
+		int count = 0;
+		int timeStamp = 0;
+		int stepValue = granularityValue;
+		int samplingInterval = (Integer) NpiInstanceRepository.getInstance().activeUidGetPersistState("com.nokia.carbide.cpp.pi.address.samplingInterval"); //$NON-NLS-1$
+		boolean exit = false;
+		
+		Hashtable<ProfiledBinary,Integer> percentages = new Hashtable<ProfiledBinary,Integer>();
+		PIVisualSharedData shared = this.getSharedDataInstance();
+		
+	    if (basedOnThreads)
+	    {
+	    	selectedItems = shared.GPP_SelectedThreadNames;
+		    if (selectedItems == null)
+		    {
+		        selectedItems = new String[0];
+		    }
+		    int[] tmpThreadIds = new int[selectedItems.length];
+		    for (int i = 0; i < selectedItems.length; i++)
+		    {
+		        String tmp = selectedItems[i].substring(selectedItems[i].lastIndexOf('_') + 1,
+		                selectedItems[i].length());
+		        tmpThreadIds[i] = Integer.parseInt(tmp);
+		    }
+		    selectedThreadIds = tmpThreadIds;
+		}
+		else
+		{
+		    selectedItems = shared.GPP_SelectedFunctionNames;
+		    if (selectedItems == null) 
+	        {
+		        selectedItems = new String[0];
+	        }
+		    int[] tmpHashCodes = new int[selectedItems.length];
+		    for (int i = 0; i < selectedItems.length; i++)
+		    {
+		        String tmp = selectedItems[i];
+		        tmpHashCodes[i] = tmp.hashCode();
+		    }
+		    selectedFunctionHashCodes = tmpHashCodes;
+		}
+		
+		for (Enumeration enumer = trace.getSamples(); !exit;)
+		{
+		    exit = !enumer.hasMoreElements();
+			if (exit) 
+			{
+				// for the final samples, modify the step value
+				// so that they will also be included
+				// now there are no new samples, so proceed directly to
+				// adding the final values to the percent list
+				stepValue = count;
+			}
+			else
+			{
+			    count++;
+			    int compareValue = 0;
+			    boolean match = false;
+			    GppSample sample = (GppSample)enumer.nextElement();
+			    if (basedOnThreads)
+			    {
+				    compareValue = sample.thread.threadId.intValue();
+				    for (int i = 0; i < selectedThreadIds.length; i++)
+				    {
+				        if (compareValue == selectedThreadIds[i])
+				        {
+				            match = true;
+				            break;
+				        }
+				    }
+			    }
+				else
+				{
+				    compareValue = getFunctionName(sample).hashCode();
+				    for (int i = 0; i < selectedFunctionHashCodes.length; i++)
+				    {
+				        if (compareValue == selectedFunctionHashCodes[i])
+				        {
+				            match = true;
+				            break;
+				        }
+				    }
+				}
+			    
+			    if (match)
+			    {
+			        ProfiledBinary pb = null;
+			        String name = getFunctionName(sample);
+					if (profiledBinaries.containsKey(name))
+					{
+						pb = (ProfiledBinary)profiledBinaries.get(name);
+					}
+				
+					if (pb == null)
+					{
+						pb = new ProfiledBinary();
+						
+						pb.setNameString(name);
+						pb.setColor(((GppTrace)this.getTrace()).getBinaryColorPalette().getColor(name));
+						
+						pb.setActivityMarkCount((trace.samples.size() + granularityValue) / granularityValue + 1);
+						for (int i = 0; i < timeStamp + stepValue * samplingInterval; i += stepValue * samplingInterval)
+						{
+							pb.zeroActivityMarkValues(i);
+						}
+						profiledBinaries.put(name, pb);
+					}
+	
+					if (percentages.containsKey(pb))
+					{
+						Integer value = (Integer)percentages.get(pb);
+						value = new Integer(value.intValue()+1);
+						percentages.remove(pb);
+						percentages.put(pb,value);
+					}
+					else
+					{
+						percentages.put(pb,new Integer(1));
+					}
+			    }
+			}
+
+			if (stepValue != 0 && count == stepValue)
+			{	
+				Vector<ProfiledGeneric> v = new Vector<ProfiledGeneric>(profiledBinaries.values());
+				Enumeration<ProfiledGeneric> pfEnum = v.elements();
+				while (pfEnum.hasMoreElements())
+				{
+					ProfiledFunction updatePf = (ProfiledFunction)pfEnum.nextElement();
+					if (percentages.containsKey(updatePf))
+					{
+						int samples = ((Integer)(percentages.get(updatePf))).intValue();
+						int finalPerc = (samples * 100) / stepValue;
+						updatePf.addActivityMarkValues(timeStamp + stepValue * samplingInterval, finalPerc, samples);
+					}
+					else
+					{
+						updatePf.zeroActivityMarkValues(timeStamp + stepValue * samplingInterval);
+					}					
+				}
+				
+				percentages.clear();
+				count = 0;
+				timeStamp += stepValue * samplingInterval;
+			}
+		}
+
+		this.binaryTable.getTable().deselectAll();
+		this.binaryTable.updateProfiledAndItemData(true);
+		this.binaryTable.getTable().redraw();
+
+		// if this is not the last table, set the selected names to set up
+		// the next table
+	    if (   (drawMode == Defines.THREADS_BINARIES_FUNCTIONS)
+	    	|| (drawMode == Defines.FUNCTIONS_BINARIES_THREADS))
+	    {
+	    	this.binaryTable.setSelectedNames();
+	    }
+	    else
+	    {
+	    	// This may not be needed
+			shared.GPP_SelectedBinaryNames = new String[0];
+	    }
+	}
+	
+	// sort profiled generics by decreasing total sample count
+	private static void sortProfiledGenerics(Hashtable<String,ProfiledGeneric> prof, GppTrace gppTrace)
+	{
+		// use an insertion sort to create a sorted linked list
+		// from the hashtable values
+		Collection<ProfiledGeneric> values = prof.values();
+		Vector<ProfiledGeneric> unsorted =   new Vector<ProfiledGeneric>(values);
+		LinkedList<ProfiledGeneric> sorted = new LinkedList<ProfiledGeneric>();
+
+		Enumeration<ProfiledGeneric> prEnum = unsorted.elements();
+		while (prEnum.hasMoreElements())
+		{
+			ProfiledGeneric pg = prEnum.nextElement();
+			if (sorted.size() == 0)
+			{
+				sorted.addFirst(pg);
+			}
+			else 
+			{
+				Iterator i = sorted.iterator();
+				boolean ok = false;
+				while (i.hasNext())
+				{
+					ProfiledGeneric next = (ProfiledGeneric)i.next();
+					if (next.getTotalSampleCount() < pg.getTotalSampleCount())
+					{
+						sorted.add(sorted.indexOf(next), pg);
+						ok = true;
+						break;
+					}
+				}
+				if (!ok)
+					sorted.addLast(pg);
+			}
+		}
+		
+		// Add the sorted data 
+		Iterator<ProfiledGeneric> iterator = sorted.iterator();
+		if (sorted.size() > 0)
+		{
+			Vector<ProfiledGeneric> v = null;
+			if (sorted.get(0) instanceof ProfiledThread)
+			{
+				v = gppTrace.getSortedThreads();
+			}
+			else if (sorted.get(0) instanceof ProfiledBinary)
+			{
+				v = gppTrace.getSortedBinaries();
+			}
+			else if (sorted.get(0) instanceof ProfiledFunction)
+			{
+				v = gppTrace.getSortedFunctions();
+			}
+			if (v != null)
+			{
+				v.clear();
+				while (iterator.hasNext())
+					v.add(0, iterator.next());
+			}
+		}
+	}
+	
+	public void updateGraph()
+	{
+	    if (drawMode == Defines.BINARIES)
+	    {
+	        vPanel.refreshCumulativeThreadTable();
+	    }
+	    else if (drawMode == Defines.THREADS)
+	    {
+	        vPanel.refreshCumulativeThreadTable();
+	    }
+
+		this.repaint();
+	}
+	
+	public void updateThreadTablePriorities(Hashtable<Integer,String> priorities)
+	{
+		this.threadTable.addPriorityColumn(priorities);
+	}
+	
+	static private String stringNotFound = Messages.getString("GppTraceGraph.notFound");  //$NON-NLS-1$
+
+	static private String stringBinaryAt         = Messages.getString("GppTraceGraph.binaryAt");  //$NON-NLS-1$
+	static private String stringBinaryForAddress = Messages.getString("GppTraceGraph.binaryForAddress");  //$NON-NLS-1$
+	static private String stringBinaryNotFound   = Messages.getString("GppTraceGraph.binaryNotFound");  //$NON-NLS-1$
+
+	static private String stringFunctionAt         = Messages.getString("GppTraceGraph.functionAt"); //$NON-NLS-1$
+	static private String stringFunctionForAddress = Messages.getString("GppTraceGraph.functionForAddress"); //$NON-NLS-1$
+	static private String stringFunctionNotFound   = Messages.getString("GppTraceGraph.functionNotFound"); //$NON-NLS-1$
+	
+	public static String getBinaryName(GppSample s)
+	{
+	    String name = null;
+	    
+	    if (s.currentFunctionSym != null)
+	    	name = s.currentFunctionSym.functionBinary.binaryName;
+
+        if (   (s.currentFunctionItt != null)
+           	&& ((name == null) || name.endsWith(stringNotFound)))
+        {
+            name = s.currentFunctionItt.functionBinary.binaryName;
+        }
+	    
+	    if (   name == null
+	    	|| name.startsWith(stringBinaryAt)
+	    	|| name.startsWith(stringBinaryForAddress))
+	    {
+	        name = stringBinaryNotFound;
+	    }
+	    return name;
+	}
+	
+	public static String getFunctionName(GppSample s)
+	{
+	    String name = null;
+	    if (s.currentFunctionSym != null)
+	    	name = s.currentFunctionSym.functionName;
+	    
+        if (   (s.currentFunctionItt != null)
+        	&& ((name == null) || name.endsWith(stringNotFound)))
+        {
+        	name = s.currentFunctionItt.functionName;
+        }
+
+	    if (   (name == null)
+	    	|| (name.startsWith(stringFunctionAt))
+	    	|| (name.startsWith(stringFunctionForAddress)))
+	    {
+	        name = stringFunctionNotFound;
+	    }
+	    
+	    return name;
+	}
+	
+	public static long getFunctionAddress(GppSample s)
+	{
+	    if (s.currentFunctionSym != null)
+	    {
+	        String name = s.currentFunctionSym.functionName;
+	        if (   (s.currentFunctionItt != null)
+	        	&& (name == null || name.endsWith(Messages.getString("GppTraceGraph.notFound"))))  //$NON-NLS-1$
+	        {
+        		return s.currentFunctionItt.startAddress.longValue();
+	        }
+	        else
+	        {
+	        	return s.currentFunctionSym.startAddress.longValue();
+	        }
+	    }
+	    else if (s.currentFunctionItt != null)
+	    {
+	        if (s.currentFunctionItt.functionName == null)
+	        {
+	        	if (s.currentFunctionSym != null)
+	        		return s.currentFunctionSym.startAddress.longValue();
+	        }
+	        else
+	        {
+        		return s.currentFunctionItt.startAddress.longValue();
+	        }
+	    }
+
+	    return 0;
+	}
+
+	public int getDrawMode()
+    {
+        return drawMode;
+    }
+
+    public void setDrawMode(int drawMode)
+    {
+    	if (
+    		   (drawMode == Defines.THREADS)
+    		|| (drawMode == Defines.THREADS_FUNCTIONS)
+    		|| (drawMode == Defines.THREADS_FUNCTIONS_BINARIES)
+    		|| (drawMode == Defines.THREADS_BINARIES)
+    		|| (drawMode == Defines.THREADS_BINARIES_FUNCTIONS)
+    		|| (drawMode == Defines.BINARIES)
+    		|| (drawMode == Defines.BINARIES_THREADS)
+    		|| (drawMode == Defines.BINARIES_THREADS_FUNCTIONS)
+    		|| (drawMode == Defines.BINARIES_FUNCTIONS)
+    		|| (drawMode == Defines.BINARIES_FUNCTIONS_THREADS)
+    		|| (drawMode == Defines.FUNCTIONS)
+    		|| (drawMode == Defines.FUNCTIONS_THREADS)
+    		|| (drawMode == Defines.FUNCTIONS_THREADS_BINARIES)
+    		|| (drawMode == Defines.FUNCTIONS_BINARIES)
+    		|| (drawMode == Defines.FUNCTIONS_BINARIES_THREADS))
+    	{
+    		if (this.drawMode != drawMode) {
+    			this.setGraphImageChanged(true);
+    		}
+	        this.drawMode = drawMode;
+	        refreshMode();
+        }
+        else
+        {
+            System.out.println(Messages.getString("GppTraceGraph.unknownDrawMode"));  //$NON-NLS-1$
+            this.drawMode = Defines.THREADS;
+            refreshMode();
+        }
+    }
+    
+    private void refreshMode()
+    {
+    	this.vPanel.refreshCumulativeThreadTable();
+    }
+
+	public int getUid() {
+		return this.uid;
+	}
+	
+	public GppTraceGraph getTraceGraph() {
+		return this.thisTraceGraph;
+	}
+	
+	public void setLeftSash(Sash leftSash) {
+		this.leftSash = leftSash;
+	}
+	
+	public Sash getLeftSash() {
+		return this.leftSash;
+	}
+	
+	public void setRightSash(Sash rightSash) {
+		this.rightSash = rightSash;
+	}
+	
+	public Sash getRightSash() {
+		return this.rightSash;
+	}
+
+	public void setProfiledThreads(Vector<ProfiledGeneric> profiledThreads) {
+		this.profiledThreads = profiledThreads;
+	}
+	
+	public Vector<ProfiledGeneric> getProfiledThreads() {
+		return this.profiledThreads;
+	}
+	
+	public Vector<ProfiledGeneric> getSortedThreads() {
+		return this.sortedProfiledThreads;
+	}
+
+	public void setProfiledBinaries(Vector<ProfiledGeneric> profiledBinaries) {
+		this.profiledBinaries = profiledBinaries;
+	}
+	
+	public Vector<ProfiledGeneric> getProfiledBinaries() {
+		return this.profiledBinaries;
+	}
+	
+	public Vector<ProfiledGeneric> getSortedBinaries() {
+		return this.sortedProfiledBinaries;
+	}
+
+	public void setProfiledFunctions(Vector<ProfiledGeneric> profiledFunctions) {
+		this.profiledFunctions = profiledFunctions;
+	}
+	
+	public Vector<ProfiledGeneric> getProfiledFunctions() {
+		return this.profiledFunctions;
+	}
+	
+	public Vector<ProfiledGeneric> getSortedFunctions() {
+		return this.sortedProfiledFunctions;
+	}
+	
+	public ProfiledThreshold getThresholdThread() {
+		return thresholdThread;
+	}
+	
+	public ProfiledThreshold getThresholdBinary() {
+		return thresholdBinary;
+	}
+	
+	public ProfiledThreshold getThresholdFunction() {
+		return thresholdFunction;
+	}
+
+	public void mouseMove(org.eclipse.swt.events.MouseEvent e) {
+	}
+}