sysperfana/perfinvestigator/com.nokia.carbide.cpp.pi.button/src/com/nokia/carbide/cpp/pi/button/BupTraceGraph.java
author Matti Laitinen <matti.t.laitinen@nokia.com>
Thu, 11 Feb 2010 15:32:31 +0200
changeset 2 b9ab3b238396
child 5 844b047e260d
permissions -rw-r--r--
Initial version of Performance Investigator under EPL

/*
 * 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.button;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Vector;

import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.FigureCanvas;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.Panel;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;

import com.nokia.carbide.cpp.internal.pi.actions.SaveSamples;
import com.nokia.carbide.cpp.internal.pi.analyser.NpiInstanceRepository;
import com.nokia.carbide.cpp.internal.pi.interfaces.ISaveSamples;
import com.nokia.carbide.cpp.internal.pi.model.GenericSampledTrace;
import com.nokia.carbide.cpp.internal.pi.plugin.model.IContextMenu;
import com.nokia.carbide.cpp.internal.pi.visual.GenericTraceGraph;
import com.nokia.carbide.cpp.pi.editors.PIPageEditor;


public class BupTraceGraph extends GenericTraceGraph implements MouseMoveListener,
																MouseListener,
																IContextMenu
{
	/*
	 * Draw button text in existing Address plugin panel
	 *
	 * For each button press, draw a line from the top to below the thread/binary/function start and end
	 * indicators, but above the x-axis label that tells seconds
	 */
	
	// whether to display events
	private boolean display_events = true;

	// constants used in drawing event: line coming down with a rectangle at the end and a name underneath
	private static final int EVENT_TOPOFLINE    = 50;
	private static final int EVENT_BOTTOMOFLINE = 30;
	private static final int EVENT_RECTWIDTH    = 5;
	private static final int EVENT_RECTHEIGHT   = 5;

	private ArrayList<BupSample> matchingSamples;
	private Button eventButtons[];
	private boolean selectedEventButtons;
	
	// class to pass sample data to the save wizard
    public class SaveSampleString implements ISaveSamples {
    	boolean done = false;
    	
    	public SaveSampleString() {
		}

    	public String getData() {
    		if (done)
    			return null;
    		
			String returnString = getSampleString();
			done = true;
			return returnString;
		}

		public String getData(int size) {
 			return getData();
		}

		public int getIndex() {
			return done ? 1 : 0;
		}

		public void clear() {
			done = false;
		}
   }

	/*
	 * return the button samples selected in the interval 
	 */
	protected String getSampleString()
	{
		int startTime = (int) this.getSelectionStart();
		int endTime   = (int) this.getSelectionEnd();
		
		Vector sampleVector = ((GenericSampledTrace) this.getTrace()).samples;
		
		int i = 0;
		while (i < sampleVector.size() && ((BupSample) sampleVector.get(i)).sampleSynchTime < startTime)
			i++;
	
		String returnString = Messages.getString("BupTraceGraph.saveSamplesHeading"); //$NON-NLS-1$

		while (i < sampleVector.size() && ((BupSample) sampleVector.get(i)).sampleSynchTime <= endTime) {
			BupSample sample = (BupSample) sampleVector.get(i);
			returnString += sample.sampleSynchTime + "," + sample.getLabel() + ",\""; //$NON-NLS-1$ //$NON-NLS-2$

			String comment = sample.getComment();
			if (comment != null) {
				for (int j = 0; j < comment.length(); j++) {
					if (comment.charAt(j) == '"')
						returnString += '"';
					returnString += comment.charAt(j);
				}
			}
			returnString += "\"\n"; //$NON-NLS-1$
			i++;
		}

		return returnString;
	}

	protected void actionSaveSamples(ISaveSamples saveSamples)
	{
		new SaveSamples(saveSamples);
	}

	protected MenuItem getSaveSamplesItem(Menu menu, boolean enabled) {
	    MenuItem saveSamplesItem = new MenuItem(menu, SWT.PUSH);

		saveSamplesItem.setText(Messages.getString("BupTraceGraph.saveSamplesForInterval")); //$NON-NLS-1$
		saveSamplesItem.setEnabled(enabled);
		
		if (enabled) {
			saveSamplesItem.addSelectionListener(new SelectionAdapter() { 
				public void widgetSelected(SelectionEvent e) {
					saveEventSamples();
				}
			});
		}
	
		return saveSamplesItem;
	}

	public BupTraceGraph(int graphIndex, BupTrace trace)
	{
		super(trace);
		this.graphIndex = graphIndex;
	}

	public void paint(Panel panel, Graphics graphics)
	{
		if (!display_events)
			return;

		Enumeration samples = ((GenericSampledTrace)this.getTrace()).samples.elements();
		graphics.setForegroundColor(ColorConstants.red);
		double scale = this.getScale();
		int height = this.getVisualSize().height;
		String eventName;

		while (samples.hasMoreElements())
		{
			BupSample sa = (BupSample)samples.nextElement();
			int x = (int)(sa.sampleSynchTime/scale);

			graphics.setForegroundColor(ColorConstants.red);
			graphics.drawLine(x, height - EVENT_TOPOFLINE, x, height - EVENT_BOTTOMOFLINE);

			// center the text under vertical line
			eventName = sa.getLabel();

			graphics.setFont(PIPageEditor.helvetica_8);

			GC gc = new GC(PIPageEditor.currentPageEditor().getSite().getShell());
			Point point = gc.stringExtent(eventName);
			gc.dispose();

			if (sa.isLabelModified()) {
				graphics.setForegroundColor(ColorConstants.blue);
			} else {
				graphics.setForegroundColor(ColorConstants.red);
			}
			graphics.drawString(eventName, x - (point.x / 2), height - EVENT_BOTTOMOFLINE + 3 + EVENT_RECTHEIGHT);

			// events with comments will have blue rectangles; otherwise, red triangles
			if ((sa.getComment() != null) && (!sa.getComment().equals(""))) //$NON-NLS-1$
			{
				graphics.setForegroundColor(ColorConstants.blue);
				graphics.setBackgroundColor(ColorConstants.blue);
			}
			else
			{
				graphics.setBackgroundColor(ColorConstants.red);
			}
			graphics.drawLine(x , height - EVENT_BOTTOMOFLINE + 1, x, height - EVENT_BOTTOMOFLINE + 2);
			graphics.fillRectangle(x - (EVENT_RECTWIDTH / 2), height - EVENT_BOTTOMOFLINE + 3,
									EVENT_RECTWIDTH, EVENT_RECTHEIGHT);
		}
	}

	public void repaint()
	{
	}

	public void refreshDataFromTrace()
	{
	}

	public void action(String action)
	{
		// do/don't show events in graph
		if (   action.equals("button_events_on") //$NON-NLS-1$
			|| action.equals("button_events_off")) //$NON-NLS-1$
  		{
  			this.display_events = action.equals(Messages.getString("BupTraceGraph.button.events.on")); //$NON-NLS-1$
  			this.parentComponent.repaintComponent();
  		} else if (action.equals("button_map_switch")){ //$NON-NLS-1$
  			this.parentComponent.repaintComponent();
  		}
  	}

	public void mouseMove(MouseEvent me)
//	public void mouseHover(MouseEvent me)
	{
		if (!display_events)
			return;

		long x = me.x;
		long y = me.y;

		int height = this.getVisualSize().height;

		// make sure we're in the right area of the graph window
		if ((y < height - EVENT_BOTTOMOFLINE) || (y > height - EVENT_BOTTOMOFLINE + EVENT_RECTHEIGHT + 2))
			return;

		Enumeration samples = ((GenericSampledTrace) this.getTrace()).samples.elements();
		double scale = this.getScale();
		
//		x += ((FigureCanvas)me.getSource()).getViewport().getViewLocation().x;

		String tooltip = ""; //$NON-NLS-1$

		while (samples.hasMoreElements())
		{
			BupSample sample = (BupSample)samples.nextElement();
			long xSample = (long)(sample.sampleSynchTime/scale + 0.5);
			
			// samples are in timestamp order, so stop when xSample + EVENT_RECTWIDTH is too high
			if (x < xSample - EVENT_RECTWIDTH)
				break;

			if ((x >= xSample - EVENT_RECTWIDTH) && (x <= xSample + EVENT_RECTWIDTH))
			{
				String parsedName = sample.getLabel();
				if (!tooltip.equals("")) //$NON-NLS-1$
					tooltip += Messages.getString("BupTraceGraph.newline"); //$NON-NLS-1$
				tooltip += Messages.getString("BupTraceGraph.tooltip1") + parsedName + Messages.getString("BupTraceGraph.tooltip2") + sample.sampleSynchTime/1000.0 + Messages.getString("BupTraceGraph.tooltip3"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
				if (sample.getComment() != null)
					 tooltip += Messages.getString("BupTraceGraph.tooltip4") + sample.getComment(); //$NON-NLS-1$
			}
		}
		
		if (!tooltip.equals("")) //$NON-NLS-1$
			((FigureCanvas)me.getSource()).setToolTipText(tooltip);
	}

	public void mouseDoubleClick(MouseEvent me)
	{
		if (!display_events)
			return;

		long x = me.x;
		long y = me.y;

		int height = this.getVisualSize().height;

		// make sure we're in the right area of the graph window
		if ((y < height - EVENT_BOTTOMOFLINE) || (y > height - EVENT_BOTTOMOFLINE + EVENT_RECTHEIGHT + 2))
			return;

		// repaint if the name or comment changes
		boolean redraw = false;

		Enumeration samples = ((GenericSampledTrace)this.getTrace()).samples.elements();
		double scale = this.getScale();

		// unlike mouseMove, the x coordinate is not relative to the FigureCanvas
		x += ((FigureCanvas)me.getSource()).getViewport().getViewLocation().x;

		matchingSamples = new ArrayList<BupSample>();
		
		while (samples.hasMoreElements())
		{
			BupSample sample = (BupSample)samples.nextElement();
			long xSample = (long)(sample.sampleSynchTime/scale + 0.5);

			// samples are in timestamp order, so stop when xSample + EVENT_RECTWIDTH is too high
			if (x < xSample - EVENT_RECTWIDTH)
				break;

			if ((x >= xSample - EVENT_RECTWIDTH) && (x <= xSample + EVENT_RECTWIDTH))
			{
				matchingSamples.add(sample);
			}
		}

		if (matchingSamples.size() == 0)
			return;
	
		// let them change some information
		Display display = PIPageEditor.currentPageEditor().getEditorSite().getShell().getDisplay();

		GridData gridData;

		if (matchingSamples.size() > 1) {
			selectedEventButtons = false;

			// query for which of several to display
			Shell shell = new Shell(display, SWT.APPLICATION_MODAL | SWT.DIALOG_TRIM);
			shell.setText(Messages.getString("BupTraceGraph.chooseEvents")); //$NON-NLS-1$
			shell.setLayout(new GridLayout(2, true));
			final Shell shellFinal = shell;

			Label label = new Label(shell, SWT.LEFT);
			label.setText(Messages.getString("BupTraceGraph.selectEvents")); //$NON-NLS-1$
			label.setFont(PIPageEditor.helvetica_10);
			gridData = new GridData(GridData.FILL_HORIZONTAL);
			gridData.horizontalSpan = 2;
			label.setLayoutData(gridData);

			eventButtons = new Button[matchingSamples.size()];

			for (int i = 0; i < matchingSamples.size(); i++) {
				eventButtons[i] = new Button(shell, SWT.CHECK);
				gridData = new GridData(GridData.FILL_HORIZONTAL);
				gridData.horizontalSpan = 2;
				eventButtons[i].setLayoutData(gridData);
				
				BupSample sample = matchingSamples.get(i);
				
				String parsedName = sample.getLabel();
				eventButtons[i].setText(Messages.getString("BupTraceGraph.buttonString1") + parsedName + Messages.getString("BupTraceGraph.buttonString2") + sample.sampleSynchTime/1000d + Messages.getString("BupTraceGraph.buttonString3")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
				eventButtons[i].setFont(PIPageEditor.helvetica_10);
			}
			
			// create the OK button
			Button okButton = new Button(shell, SWT.NONE);
			okButton.setText(Messages.getString("BupTraceGraph.ok")); //$NON-NLS-1$
			gridData = new GridData(GridData.HORIZONTAL_ALIGN_CENTER);
			okButton.setLayoutData(gridData);

			// add the listener(s)
			okButton.addSelectionListener(new SelectionListener(){
				public void widgetSelected(SelectionEvent e) {
					selectedEventButtons = true;
					for (int i = matchingSamples.size() - 1; i >= 0; i--)
						if (eventButtons[i].getSelection() == false)
							matchingSamples.remove(i);

					shellFinal.close();
				}

				public void widgetDefaultSelected(SelectionEvent e) {
					widgetSelected(e);
				}
			});

			// create the Cancel button
			Button cancelButton = new Button(shell, SWT.NONE);
			cancelButton.setText(Messages.getString("BupTraceGraph.cancel")); //$NON-NLS-1$
			gridData = new GridData(GridData.HORIZONTAL_ALIGN_CENTER);
			cancelButton.setLayoutData(gridData);

			// add the listener(s)
			cancelButton.addSelectionListener(new SelectionListener(){
				public void widgetSelected(SelectionEvent e) {
					shellFinal.close();
				}

				public void widgetDefaultSelected(SelectionEvent e) {
					widgetSelected(e);
				}
			});

			shell.pack();
			shell.open();

			while (!shell.isDisposed()) {
				if (!display.readAndDispatch()) {
					display.sleep();
				}
			}

			if (selectedEventButtons == false)
				matchingSamples.clear();
		}

		IBupEventMap map = ((BupTrace)this.getTrace()).getCurrentBupMapInUse();
		for (int i = 0; i < matchingSamples.size(); i++)
		{
			BupSample sample = matchingSamples.get(i);
			
			String enumString = map.getEnum(sample.getKeyCode());

			BupEventDialog eventDialog = new BupEventDialog(PIPageEditor.currentPageEditor().getEditorSite().getShell(), Messages.getString("BupTraceGraph.buttonDialog"), //$NON-NLS-1$
														sample.getKeyCode(), enumString, sample.getLabel(), sample.getComment(), false, sample.sampleSynchTime);
			eventDialog.open();

			if (   (eventDialog.getNewName() != null)
				&& (!eventDialog.getNewName().equals(sample.getLabel()))) {
				sample.setLabel(eventDialog.getNewName());
				redraw = true;
			}

			if (   (eventDialog.getNewComment() != null)
				&& (!eventDialog.getNewComment().equals(sample.getComment()))) {
				sample.setComment(eventDialog.getNewComment());
				redraw = true;
			}
			
			if (eventDialog.getNewSamePropagate()) {
				Vector<BupSample> allSamples = (Vector<BupSample>)((GenericSampledTrace)this.getTrace()).samples;
				for (BupSample currentSample : allSamples) {
					if (currentSample.getKeyCode() == sample.getKeyCode()) {
						currentSample.setLabel(eventDialog.getNewName());
					}
				}
				redraw = true;
			}
		}

		if (redraw)
			((FigureCanvas)me.getSource()).redraw();
	}

	public void mouseDragged(MouseEvent me) {}

	public void mouseEntered(MouseEvent me) {}

	public void mouseExited(MouseEvent me) {}

	public void mouseDown(MouseEvent me) {}

	public void mouseUp(MouseEvent me) {}

	public static boolean openButtonDialog(int buttonIndex)
	{
		boolean redraw = false;

		BupTrace bupTrace = (BupTrace)NpiInstanceRepository.getInstance().activeUidGetTrace("com.nokia.carbide.cpp.pi.button"); //$NON-NLS-1$

		if (buttonIndex > bupTrace.samples.size() || buttonIndex < 1)
			return false;

		BupSample sample = bupTrace.getBupSample(buttonIndex - 1);

		// let them change some information
		Display display = PIPageEditor.currentPageEditor().getEditorSite().getShell().getDisplay();

		GridData gridData;

		IBupEventMap map = bupTrace.getCurrentBupMapInUse();
		String enumString = map.getEnum(sample.getKeyCode());

		BupEventDialog eventDialog = new BupEventDialog(PIPageEditor.currentPageEditor().getEditorSite().getShell(), Messages.getString("BupTraceGraph.buttonDialog"), //$NON-NLS-1$
													sample.getKeyCode(), enumString, sample.getLabel(), sample.getComment(), false, sample.sampleSynchTime);
		eventDialog.open();

		if (   (eventDialog.getNewName() != null)
			&& (!eventDialog.getNewName().equals(sample.getLabel()))) {
			sample.setLabel(eventDialog.getNewName());
			redraw = true;
		}

		if (   (eventDialog.getNewComment() != null)
			&& (!eventDialog.getNewComment().equals(sample.getComment()))) {
			sample.setComment(eventDialog.getNewComment());
			redraw = true;
		}
			
		if (eventDialog.getNewSamePropagate()) {
			Vector<BupSample> allSamples = (Vector<BupSample>)bupTrace.samples;
			for (BupSample currentSample : allSamples) {
				if (currentSample.getKeyCode() == sample.getKeyCode()) {
					currentSample.setLabel(eventDialog.getNewName());
				}
			}
			redraw = true;
		}
		
		return true;
	}

	public void addContextMenuItems(Menu menu, MouseEvent me)
	{
		if (!display_events)
			return;

		long x = me.x;
		long y = me.y;

		int height = this.getVisualSize().height;

		// make sure we're in the right area of the graph window
		if ((y < height - EVENT_BOTTOMOFLINE) || (y > height - EVENT_BOTTOMOFLINE + EVENT_RECTHEIGHT + 2))
			return;

		Enumeration samples = ((GenericSampledTrace) this.getTrace()).samples.elements();
		double scale = this.getScale();

		boolean found = false;

		// unlike mouseMove, the x coordinate is not relative to the FigureCanvas
		x += ((FigureCanvas)me.getSource()).getViewport().getViewLocation().x;

		while (samples.hasMoreElements())
		{
			BupSample sample = (BupSample)samples.nextElement();
			long xSample = (long)(sample.sampleSynchTime/scale + 0.5);

			// samples are in timestamp order, so stop when xSample + EVENT_RECTWIDTH is too high
			if (x < xSample - EVENT_RECTWIDTH)
				break;

			if ((x >= xSample - EVENT_RECTWIDTH) && (x <= xSample + EVENT_RECTWIDTH))
			{
				found = true;
				break;
			}
		}

		if (!found)
			return;

		new MenuItem(menu, SWT.SEPARATOR);

		final MouseEvent meFinal = me;

		MenuItem changeEventItem = new MenuItem(menu, SWT.PUSH);
		changeEventItem.setText(Messages.getString("BupTraceGraph.changeEvent")); //$NON-NLS-1$
		changeEventItem.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				mouseDoubleClick(meFinal);
			}
		});

		int startTime = (int) this.getSelectionStart();
		int endTime   = (int) this.getSelectionEnd();

		// save raw samples
		Vector sampleVector = ((GenericSampledTrace) this.getTrace()).samples;
		
		int i = 0;
		while (i < sampleVector.size() && ((BupSample) sampleVector.get(i)).sampleSynchTime < startTime)
			i++;
		
		// enable if we have at least one event in the interval
		getSaveSamplesItem(menu, (i < sampleVector.size() && ((BupSample) sampleVector.get(i)).sampleSynchTime <= endTime));
	}
	
	public void saveEventSamples() {
    	SaveSampleString saveSampleString = new SaveSampleString();
    	actionSaveSamples(saveSampleString); //$NON-NLS-1$
	}

	public void paintLeftLegend(FigureCanvas figureCanvas, GC gc) {
	}
}