sysperfana/perfinvestigator/com.nokia.carbide.cpp.pi.power/src/com/nokia/carbide/cpp/pi/power/PowerTraceGraph.java
changeset 2 b9ab3b238396
child 5 844b047e260d
equal deleted inserted replaced
1:1050670c6980 2:b9ab3b238396
       
     1 /*
       
     2  * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). 
       
     3  * All rights reserved.
       
     4  * This component and the accompanying materials are made available
       
     5  * under the terms of the License "Eclipse Public License v1.0"
       
     6  * which accompanies this distribution, and is available
       
     7  * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8  *
       
     9  * Initial Contributors:
       
    10  * Nokia Corporation - initial contribution.
       
    11  *
       
    12  * Contributors:
       
    13  *
       
    14  * Description: 
       
    15  *
       
    16  */
       
    17 
       
    18 package com.nokia.carbide.cpp.pi.power;
       
    19 
       
    20 import java.awt.Dimension;
       
    21 import java.awt.event.ActionEvent;
       
    22 import java.awt.event.ActionListener;
       
    23 import java.text.DecimalFormat;
       
    24 import java.util.Enumeration;
       
    25 import java.util.Hashtable;
       
    26 import java.util.Vector;
       
    27 
       
    28 import org.eclipse.draw2d.ColorConstants;
       
    29 import org.eclipse.draw2d.FigureCanvas;
       
    30 import org.eclipse.draw2d.Graphics;
       
    31 import org.eclipse.draw2d.MouseEvent;
       
    32 import org.eclipse.draw2d.MouseMotionListener;
       
    33 import org.eclipse.draw2d.Panel;
       
    34 import org.eclipse.swt.SWT;
       
    35 import org.eclipse.swt.events.SelectionAdapter;
       
    36 import org.eclipse.swt.events.SelectionEvent;
       
    37 import org.eclipse.swt.graphics.Color;
       
    38 import org.eclipse.swt.graphics.GC;
       
    39 import org.eclipse.swt.graphics.Point;
       
    40 import org.eclipse.swt.graphics.RGB;
       
    41 import org.eclipse.swt.graphics.Rectangle;
       
    42 import org.eclipse.swt.widgets.Display;
       
    43 import org.eclipse.swt.widgets.Event;
       
    44 import org.eclipse.swt.widgets.Menu;
       
    45 import org.eclipse.swt.widgets.MenuItem;
       
    46 
       
    47 import com.nokia.carbide.cpp.internal.pi.actions.SaveSamples;
       
    48 import com.nokia.carbide.cpp.internal.pi.analyser.NpiInstanceRepository;
       
    49 import com.nokia.carbide.cpp.internal.pi.interfaces.ISaveSamples;
       
    50 import com.nokia.carbide.cpp.internal.pi.model.GenericSampledTrace;
       
    51 import com.nokia.carbide.cpp.internal.pi.plugin.model.IContextMenu;
       
    52 import com.nokia.carbide.cpp.internal.pi.power.actions.PowerSettingsDialog;
       
    53 import com.nokia.carbide.cpp.internal.pi.power.actions.PowerStatisticsDialog;
       
    54 import com.nokia.carbide.cpp.internal.pi.visual.GenericTraceGraph;
       
    55 import com.nokia.carbide.cpp.internal.pi.visual.GraphComposite;
       
    56 import com.nokia.carbide.cpp.internal.pi.visual.PICompositePanel;
       
    57 import com.nokia.carbide.cpp.internal.pi.visual.PIEvent;
       
    58 import com.nokia.carbide.cpp.internal.pi.visual.PIEventListener;
       
    59 import com.nokia.carbide.cpp.pi.address.GppSample;
       
    60 import com.nokia.carbide.cpp.pi.address.GppTrace;
       
    61 import com.nokia.carbide.cpp.pi.editors.PIPageEditor;
       
    62 import com.nokia.carbide.cpp.pi.util.ColorPalette;
       
    63 
       
    64 
       
    65 public class PowerTraceGraph extends GenericTraceGraph implements ActionListener,
       
    66 																  PIEventListener,
       
    67 																  MouseMotionListener,
       
    68 																  IContextMenu
       
    69 {
       
    70 	
       
    71     private int[] DTrace; // used for synchronizing the power and gpptraces.
       
    72 	private int[] DPower;
       
    73 	
       
    74 	// 3 tabs can share the same trace, but they need different graphs
       
    75     private PwrTrace trace;
       
    76     
       
    77 	private FigureCanvas leftFigureCanvas;
       
    78 	
       
    79 	// used to draw the text for the power line in the graph window.
       
    80 	private int mPowerLineY = 0;
       
    81 	
       
    82     public int x = 400;
       
    83     public int y = 800;
       
    84 
       
    85     private double averageConsumption = (float)0.0;
       
    86 	private int averageComsumptionLastOffset = Integer.MAX_VALUE;
       
    87     private double cumulative = (float)0.0;
       
    88     private double energy = 0.0f;
       
    89     private int[] sampleTimes;
       
    90     private int[] ampValues;
       
    91     private int[] voltValues;
       
    92 //    private int[] capaValues;
       
    93     private double maxAmps = Integer.MIN_VALUE;
       
    94 	private double minAmps = Integer.MAX_VALUE;
       
    95 	private double maxPower = 0.0;
       
    96     private boolean mSelecting = false;
       
    97 	
       
    98 	// used when determining when to draw the text over the power bar.
       
    99 	private int leftBorder = 0;
       
   100 	
       
   101 	private static int xLegendHeight = 20;
       
   102 	
       
   103 	boolean mShowPowerLine = true;
       
   104 	
       
   105 	private static DecimalFormat powerFormat   = new DecimalFormat(Messages.getString("powerFormat")); //$NON-NLS-1$
       
   106 	private static DecimalFormat voltageFormat = new DecimalFormat(Messages.getString("voltageFormat")); //$NON-NLS-1$
       
   107 	
       
   108 	private int uid;
       
   109 	
       
   110 	protected static int SAMPLES_AT_ONE_TIME = 1000;
       
   111 	protected int stringTime;
       
   112 
       
   113 	
       
   114 	// class to pass sample data to the save wizard
       
   115     public class SaveSampleString implements ISaveSamples {
       
   116 		int startTime;
       
   117 		int endTime;
       
   118     	
       
   119     	public SaveSampleString() {
       
   120 		}
       
   121 
       
   122     	public String getData() {
       
   123     		return getSampleString(SAMPLES_AT_ONE_TIME, this.startTime, this.endTime);
       
   124 		}
       
   125 
       
   126 		public int getIndex() {
       
   127 			if (stringTime == (int) (getSelectionStart() + 0.0005))
       
   128 				return 0;
       
   129 
       
   130 			return stringTime;
       
   131 		}
       
   132 
       
   133 		public void clear() {
       
   134 			this.startTime = (int) (getSelectionStart() + 0.0005);
       
   135 			this.endTime   = (int) (getSelectionEnd() + 0.0005);
       
   136 			stringTime = startTime;
       
   137 		}
       
   138     }
       
   139 
       
   140 	/*
       
   141 	 * return the power samples selected in the interval 
       
   142 	 */
       
   143 	protected String getSampleString(int count, int startTime, int endTime)
       
   144 	{
       
   145 		Vector sampleVector = ((PwrTrace) this.getTrace()).samples;
       
   146 		PwrSample lastSample = (PwrSample) sampleVector.get(sampleVector.size() - 1);
       
   147 		
       
   148 		String returnString = null;
       
   149 		
       
   150 		if (this.stringTime == startTime) {
       
   151 			returnString = Messages.getString("PowerTraceGraph.saveSamplesHeading"); //$NON-NLS-1$
       
   152 		}
       
   153 
       
   154 		this.stringTime++;
       
   155 
       
   156 		// check if we have returned everything
       
   157 		if ((this.stringTime > lastSample.sampleSynchTime) || (this.stringTime > endTime)) {
       
   158 			this.stringTime = endTime + 1;
       
   159 			return returnString;
       
   160 		}
       
   161 		
       
   162 		double oldCurrent  = -1;
       
   163 		double oldVoltage  = -1;
       
   164 		double oldCapacity = -1;
       
   165 		String string = ""; //$NON-NLS-1$
       
   166 
       
   167 		if (this.trace.isComplete()) {
       
   168 			for ( ;
       
   169 				 (this.stringTime < endTime + 1) && (count > 0) && (this.stringTime < sampleVector.size());
       
   170 				 this.stringTime++) {
       
   171 				PwrSample sample = (PwrSample) sampleVector.get(stringTime);
       
   172 				double current  = sample.current;
       
   173 				double voltage  = sample.voltage;
       
   174 				double capacity = sample.capacity;
       
   175 				
       
   176 				if ((oldCurrent != current) || (oldVoltage != voltage) || (oldCapacity != capacity)) {
       
   177 					string = Messages.getString("PowerTraceGraph.comma") + (int) current + Messages.getString("PowerTraceGraph.comma")  + (int) voltage + Messages.getString("PowerTraceGraph.comma") + (int) capacity + "\n"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
       
   178 					oldCurrent  = current;
       
   179 					oldVoltage  = voltage;
       
   180 					oldCapacity = capacity;
       
   181 				}
       
   182 	
       
   183 				returnString += sample.sampleSynchTime + string;
       
   184 				count--;
       
   185 			}
       
   186 		} else {
       
   187 			int i = 0;
       
   188 			
       
   189 			//find least sampling time greater than or equal to the start index
       
   190 			for ( ; i < sampleVector.size(); i++) {
       
   191 				if (((PwrSample) sampleVector.get(i)).sampleSynchTime > this.stringTime)
       
   192 					break;
       
   193 			}
       
   194 
       
   195 			if (i != 0)
       
   196 				i--;
       
   197 
       
   198 			for ( ; i < sampleVector.size() && (count > 0); i++) {
       
   199 				PwrSample sample = (PwrSample) sampleVector.get(i);
       
   200 				
       
   201 				this.stringTime = (int) sample.sampleSynchTime;
       
   202 				if (sample.sampleSynchTime > endTime)
       
   203 					break;
       
   204 				
       
   205 				double current  = sample.current;
       
   206 				double voltage  = sample.voltage;
       
   207 				double capacity = sample.capacity;
       
   208 				
       
   209 				returnString += sample.sampleSynchTime + Messages.getString("PowerTraceGraph.comma") + (int) current + Messages.getString("PowerTraceGraph.comma")  + (int) voltage + Messages.getString("PowerTraceGraph.comma") + (int) capacity + "\n"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
       
   210 				count--;
       
   211 			}
       
   212 		}
       
   213 
       
   214 		// check if we have returned everything
       
   215 		if (this.stringTime >= lastSample.sampleSynchTime) {
       
   216 			this.stringTime = endTime + 1;
       
   217 		}
       
   218 
       
   219 		return returnString;
       
   220 	}
       
   221 	
       
   222 	protected void actionSaveSamples(ISaveSamples saveSamples)
       
   223 	{
       
   224 		new SaveSamples(saveSamples);
       
   225 	}
       
   226 
       
   227 	protected MenuItem getSaveSamplesItem(Menu menu, boolean enabled) {
       
   228 	    MenuItem saveSamplesItem = new MenuItem(menu, SWT.PUSH);
       
   229 
       
   230 		saveSamplesItem.setText(Messages.getString("PowerTraceGraph.saveSamplesForInterval")); //$NON-NLS-1$
       
   231 		saveSamplesItem.setEnabled(enabled);
       
   232 		
       
   233 		if (enabled) {
       
   234 			saveSamplesItem.addSelectionListener(new SelectionAdapter() { 
       
   235 				public void widgetSelected(SelectionEvent e) {
       
   236 					saveEventSamples();
       
   237 				}
       
   238 			});
       
   239 		}
       
   240 	
       
   241 		return saveSamplesItem;
       
   242 	}
       
   243 	
       
   244 	public void saveEventSamples() {
       
   245     	SaveSampleString saveSampleString = new SaveSampleString();
       
   246     	actionSaveSamples(saveSampleString); //$NON-NLS-1$
       
   247 	}
       
   248 
       
   249     public PowerTraceGraph( int graphIndex, int uid, PwrTrace trace )
       
   250     {
       
   251         super((GenericSampledTrace)trace);
       
   252 		this.graphIndex     = graphIndex;
       
   253 		this.uid			= uid;
       
   254        
       
   255         if ( trace != null ) 
       
   256 		{
       
   257             this.trace = trace;
       
   258 
       
   259             if (this.trace.getSampleTimes() == null)
       
   260             	this.trace.initData();
       
   261 
       
   262 			this.sampleTimes = this.trace.getSampleTimes();
       
   263 			this.ampValues   = this.trace.getAmpValues();
       
   264 			this.voltValues  = this.trace.getVoltValues();
       
   265 //			this.capaValues  = this.trace.getCapaValues();
       
   266 			this.maxAmps  = this.trace.getMaxAmps();
       
   267 			this.minAmps  = this.trace.getMinAmps();
       
   268 			this.maxPower = this.trace.getMaxPower();
       
   269         }
       
   270     }
       
   271     
       
   272 	public int getUid() {
       
   273 		return this.uid;
       
   274 	}
       
   275     
       
   276 	// This method is called when widgets in the PowerInfoPanel are
       
   277 	// manipulated.
       
   278 	//
       
   279 	public void action(String actionString)
       
   280 	{   
       
   281 		if (actionString.equals("show_average")) //$NON-NLS-1$
       
   282 		{
       
   283 			// show average power as a line
       
   284 			mShowPowerLine = true;
       
   285 		}
       
   286 		else if (actionString.equals("hide_average")) //$NON-NLS-1$
       
   287 		{
       
   288 			// do not show average power as a line
       
   289 			mShowPowerLine = false;
       
   290 		}
       
   291 		else if (actionString.equals("changeVoltage")) //$NON-NLS-1$
       
   292 		{
       
   293 			// voltage changed, so compute new maximum power
       
   294 			this.trace.scaleMaxPower();
       
   295 			this.maxPower = this.trace.getMaxPower();
       
   296         }
       
   297 		else if (actionString.equals("changeBatterySize"))  //$NON-NLS-1$
       
   298 		{
       
   299 			// battery size changed, so repaint
       
   300         }
       
   301 		else
       
   302 			return;
       
   303 
       
   304         this.repaint();
       
   305 		if (this.leftFigureCanvas != null)
       
   306 			this.leftFigureCanvas.redraw();
       
   307     }
       
   308 
       
   309     public void piEventReceived(PIEvent be)
       
   310 	{
       
   311 	    switch (be.getType())
       
   312 	    {
       
   313 	    case (PIEvent.SELECTION_AREA_CHANGED):
       
   314 
       
   315 			// send this message to the 2 other graphs
       
   316 			PIEvent be2 = new PIEvent(be.getValueObject(),
       
   317 					PIEvent.SELECTION_AREA_CHANGED2);
       
   318 
       
   319 	    	for (int i = 0; i < 3; i++)
       
   320 	    	{
       
   321 	    		PowerTraceGraph graph = trace.getPowerGraph(i, getUid());
       
   322 	    		
       
   323 	    		if (graph != this) {
       
   324 					graph.piEventReceived(be2);
       
   325 	    		}
       
   326 	    	}
       
   327 
       
   328 		// FALL THROUGH
       
   329 		case PIEvent.SELECTION_AREA_CHANGED2:
       
   330 			double[] values = (double[])be.getValueObject();
       
   331 			this.setSelectionStart(values[0]);
       
   332 			this.setSelectionEnd(values[1]);
       
   333 			this.calcValues();
       
   334 			mSelecting = true;
       
   335             break;
       
   336 
       
   337 		case (PIEvent.MOUSE_PRESSED):
       
   338 			this.calcValues();	
       
   339         	this.parentComponent.getSashForm().redraw();
       
   340 			break;
       
   341 
       
   342 		case PIEvent.SCROLLED:
       
   343 			Event event = ((Event)be.getValueObject());
       
   344 			this.parentComponent.setScrolledOrigin(event.x, event.y);
       
   345 			this.repaint();
       
   346 			break;
       
   347 
       
   348 		default:
       
   349         	break;
       
   350 	    }
       
   351 	}
       
   352 	
       
   353 	public void refreshDataFromTrace()
       
   354 	{
       
   355 	}
       
   356 
       
   357 	public void enablePowerLine( boolean state )
       
   358 	{
       
   359 		mShowPowerLine = state;
       
   360 	}
       
   361 
       
   362 	public void actionPerformed ( ActionEvent ae ) 
       
   363 	{
       
   364         if( ae.getActionCommand().equals("switch") )  //$NON-NLS-1$
       
   365 		{
       
   366             parentComponent.piEventReceived( new PIEvent( "switch_gpp", PIEvent.PLUGIN_STRING_MESSAGE) ); //$NON-NLS-1$
       
   367         } 
       
   368         this.repaint();
       
   369     }	
       
   370     
       
   371     public PICompositePanel getParentComponent() {
       
   372         return this.parentComponent;
       
   373     }
       
   374     
       
   375     public float getVoltage() 
       
   376 	{
       
   377         if ( trace != null )
       
   378             return trace.getVoltage();
       
   379             
       
   380         return 0.0f;
       
   381     }
       
   382     
       
   383     public void setVoltage( float newVal ) 
       
   384 	{
       
   385         if ( trace != null )
       
   386             trace.setVoltage(newVal);
       
   387     }
       
   388     
       
   389     public double getAverageConsumption() 
       
   390 	{	
       
   391         if ( trace != null ) 
       
   392 		{
       
   393 			if( averageComsumptionLastOffset != trace.getOffset() )
       
   394 			{
       
   395 				averageComsumptionLastOffset = trace.getOffset();
       
   396 				// not calculated yet
       
   397 				calcValues();
       
   398 			}
       
   399 			
       
   400             return this.averageConsumption * trace.getVoltage();
       
   401         } 
       
   402 		
       
   403 		return 0.0f;
       
   404     }
       
   405     
       
   406     public void setOffset( int newOffset ) 
       
   407 	{   
       
   408 	    if ( trace != null )
       
   409 			trace.setOffset( newOffset );
       
   410 	}
       
   411     
       
   412     public void increaseOffset() 
       
   413 	{
       
   414         if ( trace != null )
       
   415 		{
       
   416             trace.setOffset( trace.getOffset() + 50 );
       
   417 		}
       
   418     }
       
   419     
       
   420     public void decreaseOffset() 
       
   421 	{
       
   422         if ( trace != null )
       
   423 		{
       
   424             trace.setOffset( trace.getOffset() - 50 );
       
   425 		}
       
   426     }
       
   427     
       
   428     public void setSize(int x, int y)
       
   429 	{
       
   430 	    this.x = x;
       
   431 	    this.y = y;
       
   432 	}
       
   433 
       
   434     public Dimension getSize()
       
   435 	{
       
   436 	    return new Dimension(x, y);
       
   437 	}
       
   438 
       
   439 	public void paint(Panel panel, Graphics graphics)
       
   440 	{
       
   441 		this.setSize(this.getSize().width, getVisualSize().height);
       
   442 	    this.drawDottedLineBackground(graphics, PowerTraceGraph.xLegendHeight);
       
   443 	    this.drawPowerData(graphics, PowerTraceGraph.xLegendHeight);
       
   444 
       
   445 	    // draws the same selection as the Address/Thread trace
       
   446 		this.drawSelectionSection(graphics, PowerTraceGraph.xLegendHeight);
       
   447 
       
   448 		if (mShowPowerLine)
       
   449 			this.drawPowerLine(graphics);		
       
   450 	}
       
   451 
       
   452     public void repaint()
       
   453 	{   
       
   454 	    this.parentComponent.repaintComponent();
       
   455 	}
       
   456     	
       
   457 	private void showPowerValueAtX(MouseEvent me)
       
   458 	{
       
   459 		if (me.y > this.getVisualSizeY() - PowerTraceGraph.xLegendHeight) {
       
   460 			this.setToolTipText(null);
       
   461 			return;
       
   462 		}
       
   463 		
       
   464 		// scale the value of x
       
   465 		int x = (int) (me.x * this.getScale() + 0.5);
       
   466 		
       
   467 		if (x > (int) (PIPageEditor.currentPageEditor().getMaxEndTime() * 1000 + 0.0005)) {
       
   468 			this.setToolTipText(null);
       
   469 			return;
       
   470 		}
       
   471 		
       
   472 		if (x > trace.getLastSampleNumber())
       
   473 			x = trace.getLastSampleNumber();
       
   474 
       
   475 		String textToShow = Double.toString(x / 1000.0)
       
   476 							+ Messages.getString("tooltip1"); //$NON-NLS-1$
       
   477 
       
   478 		// We could instead use the measured voltage: voltValues[x +/- movement]/1000.0 rather than the user-specified voltage?
       
   479 		double voltage = trace.getVoltage();
       
   480 
       
   481 		int movement = trace.getOffset();
       
   482 		int ampValue = 0;
       
   483 
       
   484 		// find the amperage for x
       
   485 		int index = -1;
       
   486 		if (movement == 0)
       
   487 		{
       
   488 			index = timeIndex(x);
       
   489 			if (index != -1)
       
   490 				ampValue = ampValues[index];
       
   491 		}
       
   492 		else if (movement < 0)
       
   493 		{
       
   494 			// make it positive
       
   495 			movement *= -1;
       
   496 			
       
   497 			// eat the first N=offset values.
       
   498 			if (x < sampleTimes.length - movement)
       
   499 			{
       
   500 				index = timeIndex(x + movement);
       
   501 				if (index != -1)
       
   502 					ampValue = ampValues[index];
       
   503 			}
       
   504 		}
       
   505 		else // movement > 0
       
   506 		{
       
   507 			if (x > movement)
       
   508 			{
       
   509 				index = timeIndex(x - movement);
       
   510 				if (index != -1)
       
   511 					ampValue = ampValues[index];
       
   512 			}
       
   513 		}
       
   514 
       
   515 		// determine the power = amps * voltage
       
   516 		textToShow += (int) ((ampValue * voltage) + 0.5);
       
   517 
       
   518 		this.setToolTipText(textToShow + Messages.getString("tooltip2") //$NON-NLS-1$
       
   519 							+ PowerTraceGraph.voltageFormat.format(voltage));
       
   520 	}
       
   521 	
       
   522 	public int timeIndex(int time) {
       
   523 		if (time < sampleTimes[0])
       
   524 			return -1;
       
   525 		
       
   526 		if (time >= sampleTimes[sampleTimes.length - 1])
       
   527 			return sampleTimes.length - 1;
       
   528 
       
   529 		int i = 0;
       
   530 		for ( ; sampleTimes[i] <= time; i++)
       
   531 			;
       
   532 		
       
   533 		if (sampleTimes[i] == time)
       
   534 			return i;
       
   535 		else
       
   536 			return i - 1;
       
   537 	}
       
   538 
       
   539 	private void drawPowerData(Graphics graphics, int yLegendSpace)
       
   540 	{
       
   541 		int visY = this.getVisualSize().height - yLegendSpace;
       
   542 		if (visY < 0)
       
   543 			visY = 0;
       
   544 		int sampleCount = this.sampleTimes.length;
       
   545 				
       
   546 		// arrays of values to draw
       
   547 		int points[] = new int[sampleCount * 4];
       
   548 		
       
   549 		// the offset changes when the user moves the graph or the traces are synched
       
   550 		int movement = trace.getOffset();
       
   551 		
       
   552 		// look for a move to the right ( > 0)
       
   553 		// the y value is in thisValue is the milliAmps	
       
   554 		// it doesn't matter if we render the milliAmps or mW, the graphs have the same
       
   555 		// form, it only matters when you show the values associated with the graph.
       
   556 		double maxAmps = this.maxPower / this.trace.getVoltage();
       
   557 
       
   558 		double cachedScale = this.getScale();
       
   559 		// or no movement (==0)
       
   560 		if( movement == 0 )
       
   561 		{
       
   562 			for( int i = 0, k = 0; i < sampleTimes.length; i++ )
       
   563 			{
       
   564 				points[k++] = (int)(sampleTimes[i] / cachedScale);
       
   565 				points[k++] = (int)(visY - (ampValues[i] / maxAmps) * visY);
       
   566 				if (i < sampleTimes.length - 1)
       
   567 				{
       
   568 					points[k++] = (int)(sampleTimes[i + 1] / cachedScale);
       
   569 				} else {
       
   570 					long lastTime = (int) (PIPageEditor.currentPageEditor().getMaxEndTime() * 1000 + 0.0005);
       
   571 					points[k++] = (int) (lastTime / cachedScale);
       
   572 				}
       
   573 				points[k++] = (int)(visY - (ampValues[i] / maxAmps) * visY);
       
   574 			}
       
   575 		} 
       
   576 		else if( movement > 0 )
       
   577 		{
       
   578 			// set the first N=offset values to be 0
       
   579 			for (int i = 0, k = movement * 2; i < sampleCount - movement; i++) {
       
   580 				points[k++] = sampleTimes[i];
       
   581 				points[k++] = ampValues[i];
       
   582 			}
       
   583 
       
   584 			for( int i = 0, k = 0; i < sampleCount; i++ )
       
   585 			{
       
   586 				if( i < movement )
       
   587 				{
       
   588 					points[k++] = (int)(i / cachedScale);
       
   589 					points[k++] = (int)(visY - ((float)1 / maxAmps) * visY);
       
   590 				}
       
   591 				else
       
   592 				{
       
   593 					points[k++] = (int)((points[2 * i] + movement)/cachedScale);
       
   594 					points[k++] = (int)(visY - ((float)points[1 + 2 * i] / maxAmps) * visY);
       
   595 				}
       
   596 			}
       
   597 		}
       
   598 		else
       
   599 		{
       
   600 			// make it positive
       
   601 			movement *= -1;
       
   602 			
       
   603 			// eat the first N=offset values.
       
   604 			int cutoff = sampleTimes.length - movement;
       
   605 			
       
   606 			for (int i = 0, k = movement * 2; i < sampleCount - movement; i++) {
       
   607 				points[k++] = sampleTimes[i];
       
   608 				points[k++] = ampValues[i];
       
   609 			}
       
   610 
       
   611 			for( int i = 0, k = 0; i < sampleCount; i++ )
       
   612 			{
       
   613 				if( i >= cutoff )
       
   614 				{
       
   615 					points[k++] = (int)(i / cachedScale);
       
   616 					points[k++] = (int)(visY - ((float)1 / maxAmps) * visY);
       
   617 				}
       
   618 				else
       
   619 				{
       
   620 					points[k++] = (int)((points[2 * i] - movement) / cachedScale);
       
   621 					points[k++] = (int)(visY - ((float)points[1 + 2 * i] / maxAmps) * visY);
       
   622 				}
       
   623 			}
       
   624 		}
       
   625 
       
   626 		graphics.setForegroundColor(ColorConstants.red);
       
   627 		// draw all the points at once.
       
   628 		graphics.drawPolyline(points);
       
   629 		points = null;
       
   630 	}
       
   631 
       
   632 	public double calcValueForY( int y )
       
   633 	{
       
   634 		double visY = this.getVisualSize().height - PowerTraceGraph.xLegendHeight;
       
   635 		if (visY <= 0)
       
   636 			return 0.0;
       
   637 		double maxAmps = this.maxPower / this.trace.getVoltage();
       
   638 		double yScalingFactor = maxAmps/(double)visY;
       
   639 		// visY-y to compensate for the transpose, * voltage to compenstate for the mA in the samples, we 
       
   640 		// want to show the mW values here.
       
   641 		return ( (double)(visY - (double)y) * yScalingFactor * (double)trace.getVoltage());
       
   642 	}
       
   643 	
       
   644 	public int calcYforValue( double value )
       
   645 	{
       
   646 		double visY = this.getVisualSize().height - PowerTraceGraph.xLegendHeight;
       
   647 		if ((visY <= 0) || (this.trace.getVoltage() == 0))
       
   648 			return 0;
       
   649 		double maxAmps = this.maxPower / this.trace.getVoltage();
       
   650 		double yScalingFactor = maxAmps / visY;
       
   651 
       
   652 		// visY-y to compensate for the transpose, * voltage to compenstate for the mA in the samples, we 
       
   653 		// want to show the mW values here.
       
   654 		if (yScalingFactor == 0)
       
   655 			return 0;
       
   656 
       
   657 		double tmp = value / (double)trace.getVoltage() / yScalingFactor;
       
   658 		
       
   659 		return (int)Math.ceil(visY - tmp);
       
   660 	}
       
   661 
       
   662 	private void drawPowerLine( Graphics graphics )
       
   663 	{
       
   664 		//mPowerLineY == 0  on startup.
       
   665 		boolean startup = (mPowerLineY == 0);
       
   666 
       
   667 		if( mPowerLineY == 0 || mSelecting )
       
   668 		{
       
   669 			if( mSelecting )
       
   670 			{
       
   671 				// still selecting?
       
   672 				if( ((super.getSelectionStart() == -1)  && (super.getSelectionEnd() == -1)) )
       
   673 				{
       
   674 					mSelecting = false;
       
   675 					// need to turn them back on. mouse drag events for drawing the power line.
       
   676 				}
       
   677 				else
       
   678 				{
       
   679 					mPowerLineY = calcYforValue( getAverageConsumption() );
       
   680 				}
       
   681 			}
       
   682 			
       
   683 			if( mPowerLineY == 0 )
       
   684 			{
       
   685 				mPowerLineY = calcYforValue( getAverageConsumption() );
       
   686 			}
       
   687 		}
       
   688 		
       
   689 		double powerValue = 0.0;
       
   690 		
       
   691 		String strValue = null;
       
   692 		
       
   693 		// requirement, if dragging power bar then print true power value. If
       
   694 		// selecting then print average of area not the true value of the y coordinate.
       
   695 		//
       
   696 		if( !mSelecting && !startup )
       
   697 			powerValue = calcValueForY(mPowerLineY);
       
   698 		else if( mSelecting || startup )
       
   699 			powerValue = getAverageConsumption();
       
   700 
       
   701 		strValue = PowerTraceGraph.powerFormat.format((int)(powerValue + 0.5));
       
   702 
       
   703 		// this does cause some overhead and could be removed since it only provides some aesthetics.
       
   704 		updateVisibleBorders();
       
   705 		leftBorder = this.parentComponent.getScrolledOrigin().x;
       
   706 //		leftBorder = this.getVisibleLeftBorder();
       
   707 		if( leftBorder < 0 )
       
   708 			leftBorder = 0;	
       
   709 		
       
   710 		// draw the average power line with a width of 3
       
   711 		int lineWidth = graphics.getLineWidth();
       
   712 
       
   713 		graphics.setForegroundColor(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
       
   714 		graphics.setLineWidth(2);
       
   715 		graphics.drawLine(leftBorder, mPowerLineY, this.getSize().width, mPowerLineY );
       
   716 
       
   717 		graphics.setLineWidth(lineWidth);
       
   718 
       
   719 		// figure out how big the box behind the text should be.
       
   720 		GC gc = new GC(PIPageEditor.currentPageEditor().getSite().getShell());
       
   721 		Point point = gc.stringExtent(strValue);
       
   722 		gc.dispose();
       
   723 
       
   724 		// clear the text rectangle
       
   725 		graphics.setBackgroundColor(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
       
   726 		graphics.setForegroundColor(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
       
   727 		graphics.fillRectangle(leftBorder + 20, mPowerLineY - (point.y / 2), point.x + 6, point.y );
       
   728 
       
   729 		graphics.setForegroundColor(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
       
   730 
       
   731 		// make the font bold 16, draw the text, and restore the font
       
   732 		int oldStyle  = graphics.getFont().getFontData()[0].getStyle();
       
   733 		int oldHeight = graphics.getFont().getFontData()[0].getHeight();
       
   734 
       
   735 		graphics.getFont().getFontData()[0].setStyle((oldStyle & SWT.NORMAL) | (oldStyle & SWT.ITALIC) | SWT.BOLD);
       
   736 		graphics.getFont().getFontData()[0].setHeight(16);
       
   737 		
       
   738 		graphics.drawString(strValue, leftBorder + 23, mPowerLineY - (point.y / 2));
       
   739 
       
   740 		graphics.getFont().getFontData()[0].setStyle(oldStyle);
       
   741 		graphics.getFont().getFontData()[0].setHeight(oldHeight);
       
   742 
       
   743 		if ( startup )
       
   744 			mPowerLineY = 0;
       
   745 	}
       
   746 
       
   747     public void drawPwrGraphSelection(Graphics g)
       
   748 	{	
       
   749 	    int selectionStart = (int)super.getSelectionStart();
       
   750 	    int selectionEnd = (int)super.getSelectionEnd();
       
   751 	    double scale = super.getScale();
       
   752 		
       
   753 	    if(selectionStart != -1 && selectionEnd != -1)
       
   754 	    {
       
   755 	    	Color selectColor = new Color(Display.getCurrent(),123,156,178);
       
   756 	    	
       
   757 	    	g.setForegroundColor(selectColor);
       
   758 	    	g.fillRectangle((int)(selectionStart / scale + 0.5),
       
   759 	    					0,
       
   760 	    					(int)((selectionEnd - selectionStart) / scale + 0.5),
       
   761 	    					this.getVisualSize().height - PowerTraceGraph.xLegendHeight);
       
   762 	    	selectColor.dispose();
       
   763 	    }
       
   764 	}
       
   765 	
       
   766 	// synchronize the power and software traces
       
   767 	// logically:
       
   768 	// 1) digitize the GPP and power traces
       
   769 	// 2) align the traces so that the tail of the software trace is aligned with 
       
   770 	//	  the tail of the power trace.
       
   771 	// 3) slowly move software trace to the left ADDing the software and power trace
       
   772 	// 	  values together and performing a sum until the highest total is found.
       
   773 	// 4) using the index of the highest total, either add dummy values to the power trace or
       
   774 	//    remove values from the power trace.
       
   775 	// 5) finally update the samples and refresh turn off the wait cursor.
       
   776     
       
   777 	public void doSynchronize( GppTrace gpp, PwrTrace power )
       
   778 	{
       
   779 //		System.err.println( "Starting synchronization process" );
       
   780 		digitizeGPPFile(gpp);
       
   781 		digitizePowerFile(power);
       
   782 		
       
   783 		int MAX = 0;
       
   784 		int MAX_POWER_INDEX = 0;
       
   785 		int MAX_TRACE_INDEX = 0;
       
   786 		int accum = 0;
       
   787 
       
   788 		int TOTAL_MOVEMENT = (DPower.length-DTrace.length) + (int)(0.25*DTrace.length) + 1;
       
   789 
       
   790 		// TI = trace index
       
   791 		int TI = 0;
       
   792 		// PI = power trace index
       
   793 		int PI = DPower.length-DTrace.length;
       
   794 
       
   795 		for( int j = 0; j < TOTAL_MOVEMENT; j++ )
       
   796 		{
       
   797 			for( int i = TI; i < DTrace.length; i++ )
       
   798 			{
       
   799 				if( (DTrace[i] & DPower[PI+i]) == 0 )
       
   800 				{
       
   801 					accum++;
       
   802 				}
       
   803 			}
       
   804 			if( accum > MAX )
       
   805 			{
       
   806 				MAX = accum;
       
   807 				MAX_POWER_INDEX = PI;
       
   808 				MAX_TRACE_INDEX = TI;
       
   809 			}
       
   810 			accum = 0;
       
   811 			PI--;
       
   812 			if( PI < 0 )
       
   813 			{
       
   814 				PI=0;
       
   815 				TI++;
       
   816 			}
       
   817 		}
       
   818 		// one more pass through the data to update the graphs.
       
   819 		//
       
   820 
       
   821 		if( MAX_TRACE_INDEX > 0 )
       
   822 		{
       
   823 			trace.setOffset( trace.getOffset() - MAX_TRACE_INDEX );
       
   824 		}
       
   825 		else
       
   826 		{
       
   827 			trace.setOffset( trace.getOffset() + MAX_POWER_INDEX );
       
   828 		}
       
   829 		parentComponent.getActiveGraph().getCompositePanel().getSashForm()
       
   830 								.setCursor(Display.getCurrent().getSystemCursor(SWT.CURSOR_WAIT) );
       
   831 	}
       
   832 	// digitize the power trace
       
   833 	// basically:
       
   834 	// 1) find the min and max power values in the trace
       
   835 	// 2) for each value in the trace if the value is > Half the average range
       
   836 	//    then set that value to 1 else 0.
       
   837 	//
       
   838 	public void digitizePowerFile( PwrTrace power )
       
   839 	{
       
   840 		double MIN_Value = (double)minAmps/(double)1000;
       
   841 		double MAX_Value = (double)maxAmps/(double)1000;
       
   842 		
       
   843 		// find the min and max in the power
       
   844 		//
       
   845 		// we already have this data so we can simply divide by 1000 for the scale we need.
       
   846 
       
   847 		float Half_Avg_Range = (float)((MAX_Value - MIN_Value)/2);		
       
   848 		
       
   849 		DPower = new int[power.samples.size()];
       
   850 		int DPowerIndex = 0;
       
   851 
       
   852 		// as an aside, this tracks well with the application states.
       
   853 		//
       
   854 		for( Enumeration e = power.getSamples(); e.hasMoreElements() ; )
       
   855 		{
       
   856 			PwrSample current = (PwrSample)e.nextElement();
       
   857 			if( current.current > Half_Avg_Range )
       
   858 			{
       
   859 				DPower[DPowerIndex] = 1;
       
   860 			}
       
   861 			else
       
   862 			{
       
   863 				DPower[DPowerIndex] = 0;
       
   864 			}
       
   865 			DPowerIndex++;
       
   866 		}
       
   867 	}
       
   868 	
       
   869 	// digitize the gpp file
       
   870 	// basically:
       
   871 	// 1a) divide the run into windows and for each window:
       
   872 	// 1b) count the number of transitions i.e. different functions called in the windows by putting the process
       
   873 	//    name into a hashtable, if the add returns a null value then the insert 
       
   874 	//    did not collide and we transitioned.
       
   875 	// 1c) find the min and max number of transistions for all windows
       
   876 	//
       
   877 	// 2a) for each window if the number of transitions for that window are greater
       
   878 	//	   than the average number of transtitions then set the digitized version to be 1 else 0.
       
   879 	//
       
   880 	public void digitizeGPPFile( GppTrace thisTrace )
       
   881 	{		
       
   882 		int WINDOW_SIZE = 20;
       
   883 
       
   884 		int numSamples = thisTrace.samples.size();
       
   885 		int count = 1;
       
   886 		Hashtable<String,String> histogram = new Hashtable<String,String>();
       
   887 		int windowSizes[] = new int[numSamples/WINDOW_SIZE];
       
   888 		int min = Integer.MAX_VALUE;
       
   889 		int max = Integer.MIN_VALUE;
       
   890 
       
   891 		int numTransitions = 1;
       
   892 
       
   893 		int total = 0;
       
   894 //		String lastTrace = null;
       
   895 		for( int i = 0; i < numSamples; i++ )
       
   896 		{
       
   897 			GppSample sample = thisTrace.getGppSample(i);
       
   898 			if( count % WINDOW_SIZE == 0 )
       
   899 			{
       
   900 				windowSizes[i/WINDOW_SIZE] = histogram.size() + numTransitions;
       
   901 				if( windowSizes[i/WINDOW_SIZE] < min )
       
   902 					min = windowSizes[i/WINDOW_SIZE];
       
   903 				else if( windowSizes[i/WINDOW_SIZE] > max )
       
   904 					max = windowSizes[i/WINDOW_SIZE];
       
   905 
       
   906 				total += windowSizes[i/WINDOW_SIZE];
       
   907 
       
   908 				numTransitions = 1;
       
   909 				histogram.clear();
       
   910 				count = 0;
       
   911 			}
       
   912 			count++;
       
   913 			if( histogram.put( new String(sample.thread.process.name + Messages.getString("PowerTraceGraph.histogram1") //$NON-NLS-1$
       
   914 						                  + (sample.thread.threadName != null ? sample.thread.threadName
       
   915 											   : Messages.getString("PowerTraceGraph.11")) + Messages.getString("PowerTraceGraph.12") //$NON-NLS-1$ //$NON-NLS-2$
       
   916 					   							   + sample.thread.threadId + Messages.getString("PowerTraceGraph.13") //$NON-NLS-1$
       
   917 					   							   + sample.currentFunctionSym.functionName + Messages.getString("PowerTraceGraph.14") //$NON-NLS-1$
       
   918 					   							   + Long.toHexString(sample.currentFunctionSym.startAddress.longValue()) ),
       
   919 					   			Messages.getString("PowerTraceGraph.15") ) == null ) //$NON-NLS-1$
       
   920 			{
       
   921 				numTransitions++;
       
   922 			}
       
   923 		}
       
   924 		
       
   925 		int average = (max - min) /2 ;
       
   926 
       
   927 		DTrace = new int[windowSizes.length * WINDOW_SIZE];
       
   928 		int DTraceIndex = 0;
       
   929 		for( int i = 0; i < windowSizes.length; i++ )
       
   930 		{
       
   931 			for( int j = 0; j < WINDOW_SIZE; j++ )
       
   932 			{
       
   933 				// okay, so it seems that when there is more variablity in the trace there is more constant variablity in the power.
       
   934 				if( windowSizes[i] <= average /*halfAvgRange */ )	
       
   935 				{
       
   936 					DTrace[DTraceIndex] = 0;
       
   937 				}
       
   938 				else
       
   939 				{
       
   940 					DTrace[DTraceIndex] = 1;
       
   941 				}
       
   942 				DTraceIndex++;
       
   943 			}
       
   944 		}
       
   945 	}
       
   946 
       
   947 	// calculates the average power numbers of a selection.
       
   948     private void calcValues() 
       
   949 	{
       
   950         int selStart = (int)super.getSelectionStart(); 
       
   951         int selEnd   = (int)super.getSelectionEnd();
       
   952         int sum = 0;
       
   953         int offset = trace.getOffset();
       
   954         this.cumulative = 0;
       
   955         this.averageConsumption = 0;
       
   956         this.energy = 0;
       
   957         
       
   958         if (selStart < offset)
       
   959         	selStart = offset;
       
   960 
       
   961         if (selEnd < trace.getFirstSampleNumber() || selStart > selEnd)
       
   962         	return;
       
   963         
       
   964         // find the first sample greater than or equal to selStart
       
   965         int index = timeIndex(selStart);
       
   966 
       
   967         // count time before the first sample as a bunch of zeros
       
   968         if (selStart < trace.getFirstSampleNumber()) {
       
   969         	sum = trace.getFirstSampleNumber() - selStart;
       
   970         	index = 0;
       
   971         }
       
   972         
       
   973 		for (int j = index; j < sampleTimes.length; j++)
       
   974 		{	
       
   975 			int time = sampleTimes[j] + 1;
       
   976 			if (time < selStart)
       
   977 				time = selStart;
       
   978 			
       
   979 			int nextTime = j == sampleTimes.length - 1 ? Integer.MAX_VALUE : sampleTimes[j + 1];
       
   980 			
       
   981 			int count = Math.min(nextTime - time + 1, selEnd - time + 1);
       
   982 			this.energy += ((double)ampValues[j] * (double)this.voltValues[j])/(float)1000000.0 * count;
       
   983 			this.cumulative += ampValues[j] * count;
       
   984 			sum += count;
       
   985 			time += count;
       
   986 			
       
   987 			if (time > selEnd)
       
   988 				break;
       
   989 		}
       
   990 		
       
   991 		if (sum > 0)
       
   992 			this.averageConsumption = (double)this.cumulative / sum ;     		
       
   993     }
       
   994     
       
   995     public double getCumulativeConsumption() 
       
   996 	{
       
   997         return this.energy;
       
   998     }
       
   999      
       
  1000     public float getBatterySize() {
       
  1001         if ( trace != null ) {
       
  1002             return trace.getBatterySize();
       
  1003         } else
       
  1004             return 0.0f;
       
  1005     }
       
  1006     
       
  1007     public void setBatterySize( float newVal ) {
       
  1008         if ( trace != null )
       
  1009             trace.setBatterySize( newVal );
       
  1010     }
       
  1011 	
       
  1012 	public void mouseDragged(MouseEvent me)  
       
  1013 	{
       
  1014 		int tmpY = me.y;
       
  1015 		int tmpX = me.x;
       
  1016 
       
  1017 		if( (tmpY < (this.getVisualSize().height - PowerTraceGraph.xLegendHeight)) && (tmpY > 0) && (!mSelecting))
       
  1018 		{
       
  1019 			mPowerLineY = tmpY;
       
  1020 		}
       
  1021 
       
  1022 		this.repaint();
       
  1023 	}
       
  1024 
       
  1025 	public void mouseMoved(MouseEvent me)  
       
  1026 	{
       
  1027 		showPowerValueAtX( me );
       
  1028 	}
       
  1029 
       
  1030 	public void mouseEntered(MouseEvent arg0) {
       
  1031 	}
       
  1032 
       
  1033 	public void mouseExited(MouseEvent arg0) {
       
  1034 	}
       
  1035 
       
  1036 	public void mouseHover(MouseEvent arg0) {
       
  1037 	}
       
  1038 
       
  1039 	public void addContextMenuItems(Menu menu, org.eclipse.swt.events.MouseEvent me) {
       
  1040 		
       
  1041 		new MenuItem(menu, SWT.SEPARATOR);
       
  1042 		
       
  1043 		Boolean showLine   = Boolean.TRUE;	// by default, show the interval average power as a line
       
  1044 
       
  1045 		// if there is a show average power line value associated with the current Analyser tab, then use it
       
  1046 		Object obj = NpiInstanceRepository.getInstance().getPersistState(uid, "com.nokia.carbide.cpp.pi.power.showLine");  //$NON-NLS-1$
       
  1047 		if ((obj != null) && (obj instanceof Boolean))
       
  1048 			// retrieve the current value
       
  1049 			showLine = (Boolean)obj;
       
  1050 		else
       
  1051 			// set the initial value
       
  1052 			NpiInstanceRepository.getInstance().setPersistState(uid, "com.nokia.carbide.cpp.pi.power.showLine", showLine);  //$NON-NLS-1$
       
  1053 
       
  1054 		final Boolean showLineFinal = showLine;
       
  1055 
       
  1056 		MenuItem showLineItem = new MenuItem(menu, SWT.CHECK);
       
  1057 		showLineItem.setText(Messages.getString("PowerTraceGraph.18")); //$NON-NLS-1$
       
  1058 		showLineItem.setSelection(showLine);
       
  1059 		showLineItem.addSelectionListener(new SelectionAdapter() {
       
  1060 			public void widgetSelected(SelectionEvent e) {
       
  1061 				String action;
       
  1062 				NpiInstanceRepository.getInstance().setPersistState(uid, "com.nokia.carbide.cpp.pi.power.showLine", !showLineFinal);  //$NON-NLS-1$
       
  1063 				if (!showLineFinal)
       
  1064 				{
       
  1065 					action = "show_average";  //$NON-NLS-1$
       
  1066 				} else {
       
  1067 					action = "hide_average";  //$NON-NLS-1$
       
  1068 				}
       
  1069 
       
  1070 		    	for (int i = 0; i < 3; i++)
       
  1071 		    	{
       
  1072 		    		PowerTraceGraph graph = trace.getPowerGraph(i, getUid());
       
  1073 					graph.action(action);
       
  1074 		    	}
       
  1075 			}
       
  1076 		});
       
  1077 
       
  1078 		new MenuItem(menu, SWT.SEPARATOR);
       
  1079 
       
  1080 		int startTime = (int) this.getSelectionStart();
       
  1081 		int endTime   = (int) this.getSelectionEnd();
       
  1082 
       
  1083 		// save raw samples
       
  1084 		getSaveSamplesItem(menu, (startTime != -1) && (endTime != -1) && (startTime != endTime));
       
  1085 		
       
  1086 		new MenuItem(menu, SWT.SEPARATOR);
       
  1087 
       
  1088 		MenuItem powerSettingsItem = new MenuItem(menu, SWT.PUSH);
       
  1089 		powerSettingsItem.setText(Messages.getString("PowerTraceGraph.22")); //$NON-NLS-1$
       
  1090 		powerSettingsItem.addSelectionListener(new SelectionAdapter() {
       
  1091 			public void widgetSelected(SelectionEvent e) {
       
  1092 				new PowerSettingsDialog(Display.getCurrent());
       
  1093 			}
       
  1094 		});
       
  1095 		
       
  1096 		MenuItem powerStatsItem = new MenuItem(menu, SWT.PUSH);
       
  1097 		powerStatsItem.setText(Messages.getString("PowerTraceGraph.23")); //$NON-NLS-1$
       
  1098 		powerStatsItem.addSelectionListener(new SelectionAdapter() {
       
  1099 			public void widgetSelected(SelectionEvent e) {
       
  1100 				new PowerStatisticsDialog(Display.getCurrent());
       
  1101 			}
       
  1102 		});
       
  1103 	}
       
  1104 
       
  1105 	public void paintLeftLegend(FigureCanvas figureCanvas, GC gc)
       
  1106 	{
       
  1107 		GC localGC = gc;
       
  1108 		
       
  1109 		if (gc == null)
       
  1110 			gc = new GC(PIPageEditor.currentPageEditor().getSite().getShell());
       
  1111 		
       
  1112 		if (this.leftFigureCanvas == null)
       
  1113 			this.leftFigureCanvas = figureCanvas;
       
  1114 
       
  1115 		Rectangle rect = ((GraphComposite) figureCanvas.getParent()).figureCanvas.getClientArea();
       
  1116 		
       
  1117 		double visY = rect.height - PowerTraceGraph.xLegendHeight;
       
  1118 		if (visY < 0)
       
  1119 			visY = 0;
       
  1120 		double yIncrement = visY / 10;
       
  1121 		
       
  1122 		// this assumes maxPower is evenly divisible by 10
       
  1123 		int maxPower = (int) this.maxPower;
       
  1124 		int powerIncrement = maxPower / 10;
       
  1125 
       
  1126 		gc.setForeground(ColorPalette.getColor(new RGB(100, 100, 100)));
       
  1127 		gc.setBackground(ColorPalette.getColor(new RGB(255, 255, 255)));
       
  1128 
       
  1129 		int previousBottom = 0;		// bottom of the previous legend drawn
       
  1130 		String legend;
       
  1131 
       
  1132 		// draw 11 value indicators (0..10) to the scale  
       
  1133 		int i = 0;
       
  1134 		for (double y = 0; i < 11; i++, y += yIncrement, maxPower -= powerIncrement)
       
  1135 		{
       
  1136 			// construct the text for each scale
       
  1137 			legend = (int)maxPower + Messages.getString("PowerTraceGraph.24"); //$NON-NLS-1$
       
  1138 			
       
  1139 			Point extent = gc.stringExtent(legend);
       
  1140 			
       
  1141 			gc.drawLine(GenericTraceGraph.yLegendWidth - 3, (int)y + 1, GenericTraceGraph.yLegendWidth, (int)y + 1);
       
  1142 
       
  1143 			if (y >= previousBottom)
       
  1144 			{
       
  1145 				gc.drawString(legend, GenericTraceGraph.yLegendWidth - extent.x - 4, (int)y);
       
  1146 				previousBottom = (int)y + extent.y;
       
  1147 			}
       
  1148 		}
       
  1149 
       
  1150 		if (localGC == null) {
       
  1151 			gc.dispose();
       
  1152 			figureCanvas.redraw();
       
  1153 		}
       
  1154 	}
       
  1155 }