Home | History | Annotate | Download | only in ui
      1 /*******************************************************************************
      2  * Copyright (c) 2000, 2009 IBM Corporation and others.
      3  * All rights reserved. This program and the accompanying materials
      4  * are made available under the terms of the Eclipse Public License v1.0
      5  * which accompanies this distribution, and is available at
      6  * http://www.eclipse.org/legal/epl-v10.html
      7  *
      8  * Contributors:
      9  *     IBM Corporation - initial API and implementation
     10  *******************************************************************************/
     11 package org.eclipse.test.performance.ui;
     12 
     13 import java.text.NumberFormat;
     14 import java.util.ArrayList;
     15 import java.util.List;
     16 
     17 import org.eclipse.swt.SWT;
     18 import org.eclipse.swt.graphics.Color;
     19 import org.eclipse.swt.graphics.GC;
     20 import org.eclipse.swt.graphics.Point;
     21 import org.eclipse.swt.widgets.Display;
     22 
     23 public class BarGraph {
     24 
     25 	private static final int MARGIN= 5; // margin on all four sides
     26 	private static final int BARHEIGHT= 8; // height of bar
     27 	private static final int GAP= 10; // gap between bars
     28 	private static final int TGAP= 5; // gap between lines and labels
     29 
     30 	private static final boolean NO_SCALE= true; //
     31 
     32 	// if NO_SCALE is true the following values are used:
     33 	private static final double RATIO= 0.6; // fraction of width reserved for bar graph; needs tweaking
     34 	private static final int FROM_END= 20; // a break (//) is shown this far from end of bar
     35 	private static final int SLANT= 8; // slant of break
     36 	private static final int GAP2= 5; // width of break
     37 
     38 	private StringBuffer fAreaBuffer;
     39 
     40 	private static class BarItem {
     41 
     42 		String title;
     43 		double value;
     44 		String url;
     45 		String slowdownExpected;
     46 		boolean significant;
     47 
     48 		BarItem(String t, double[] stats, String u, String slow, boolean sig) {
     49 			this.title= t;
     50 			this.value= stats[0]==0 ? 0 : -stats[0] * 100;
     51 			this.url= u;
     52 			this.slowdownExpected= slow;
     53 			this.significant= sig;
     54 		}
     55 	}
     56 
     57 	private String fTitle;
     58 	private List fItems;
     59 
     60 	BarGraph(String title) {
     61 		this.fTitle= title;
     62 		this.fItems= new ArrayList();
     63 	}
     64 
     65 	public void addItem(String name, double[] stats, String url, String slow, boolean significant) {
     66 		this.fItems.add(new BarItem(name, stats, url, slow, significant));
     67 	}
     68 
     69 	public int getHeight() {
     70 		int n= this.fItems.size();
     71 		int textHeight= 16;
     72 		int titleHeight= 0;
     73 		if (this.fTitle != null)
     74 			titleHeight= textHeight + GAP;
     75 		return MARGIN + titleHeight + n * (GAP + BARHEIGHT) + GAP + textHeight + MARGIN;
     76 	}
     77 
     78 	public void paint(Display display, int width, int height, GC gc) {
     79 
     80 		NumberFormat nf= NumberFormat.getInstance();
     81 
     82 		BarItem[] bars= (BarItem[]) this.fItems.toArray(new BarItem[this.fItems.size()]);
     83 
     84 		// draw white background
     85 		Color bg= display.getSystemColor(SWT.COLOR_WHITE);
     86 		gc.setBackground(bg);
     87 		gc.fillRectangle(0, 0, width, height);
     88 
     89 		// determine the widths of the bar and the label areas
     90 		int w;
     91 		if (NO_SCALE) {
     92 			// we use a fixed width
     93 			w= (int) (RATIO * width);
     94 		} else {
     95 			// we calculate the max width
     96 			int maxNameLength= 0;
     97 			for (int i= 0; i < bars.length; i++) {
     98 				Point es= gc.stringExtent(bars[i].title);
     99 				maxNameLength= Math.max(maxNameLength, es.x);
    100 			}
    101 			w= width - maxNameLength - TGAP - 2 * MARGIN;
    102 		}
    103 
    104 		Color fg= display.getSystemColor(SWT.COLOR_BLACK);
    105 
    106 		int vstart= 0; // start rows here
    107 		if (this.fTitle != null) {
    108 			vstart= gc.stringExtent(this.fTitle).y + GAP;
    109 			gc.drawString(this.fTitle, MARGIN, MARGIN, true); // draw title left aligned
    110 		}
    111 
    112 		int center= MARGIN + w / 2;
    113 		int w2= w / 2 - gc.stringExtent("-999.9").x - TGAP; // reserve space //$NON-NLS-1$
    114 
    115 		// determine maximum of values
    116 		double max= 0.0;
    117 		for (int i= 0; i < bars.length; i++)
    118 			max= Math.max(max, Math.abs(bars[i].value));
    119 
    120 		double d;
    121 		if (NO_SCALE) {
    122 			d= 25;
    123 			max= 125;
    124 		} else {
    125 			if (max > 400.0) {
    126 				d= 200;
    127 			} else if (max > 200.0) {
    128 				d= 100;
    129 			} else if (max > 100.0) {
    130 				d= 50;
    131 			} else if (max > 50) {
    132 				d= 25;
    133 			} else if (max > 25) {
    134 				d= 10;
    135 			} else if (max > 10) {
    136 				d= 5;
    137 			} else if (max > 5) {
    138 				d= 2.5;
    139 			} else {
    140 				d= 1.0;
    141 			}
    142 		}
    143 
    144 		// draw striped background
    145 		int y= MARGIN + vstart;
    146 		Color lightblue= new Color(display, 237, 243, 254);
    147 		gc.setBackground(lightblue);
    148 		for (int i= 0; i < bars.length; i++)
    149 			if (i % 2 == 0)
    150 				gc.fillRectangle(0, y + i * (BARHEIGHT + GAP), width, BARHEIGHT + GAP);
    151 
    152 		// draw grid
    153 		int yy= y + bars.length * (BARHEIGHT + GAP);
    154 		gc.drawLine(center, y, center, yy + TGAP);
    155 		Color grey= display.getSystemColor(SWT.COLOR_GRAY);
    156 		for (int i= 1; d * i < max; i++) {
    157 
    158 			double xx= d * i;
    159 			int x= (int) ((xx / max) * w2);
    160 
    161 			gc.setForeground(grey);
    162 			gc.drawLine(center - x, y, center - x, yy + TGAP);
    163 			gc.drawLine(center + x, y, center + x, yy + TGAP);
    164 
    165 			gc.setForeground(fg);
    166 
    167 			String s3= nf.format(-xx) + "%"; //$NON-NLS-1$
    168 			Point es3= gc.stringExtent(s3);
    169 			gc.drawString(s3, center - x - es3.x / 2, yy + TGAP, true);
    170 
    171 			String s4= nf.format(xx) + "%"; //$NON-NLS-1$
    172 			Point es4= gc.stringExtent(s4);
    173 			gc.drawString(s4, center + x - es4.x / 2, yy + TGAP, true);
    174 		}
    175 		gc.drawLine(0, yy, w, yy);
    176 
    177 		nf.setMaximumFractionDigits(1);
    178 
    179 		// link color
    180 		Color blue= display.getSystemColor(SWT.COLOR_BLUE);
    181 		// draw bars
    182 //		Color green= display.getSystemColor(SWT.COLOR_GREEN);
    183 //		Color red= display.getSystemColor(SWT.COLOR_RED);
    184 		Color green = new Color(display, 95, 191, 95);
    185 		Color red = new Color(display, 225, 50, 50);
    186 		Color gray= display.getSystemColor(SWT.COLOR_GRAY);
    187 		Color yellow= display.getSystemColor(SWT.COLOR_YELLOW);
    188 		Color white= display.getSystemColor(SWT.COLOR_WHITE);
    189 		for (int i= 0; i < bars.length; i++) {
    190 
    191 			BarItem bar= bars[i];
    192 			double delta = bar.value;
    193 			double orgDelta= delta;
    194 
    195 			boolean clamped= false;
    196 			if (NO_SCALE) {
    197 				if (delta > max) {
    198 					delta= max;
    199 					clamped= true;
    200 				} else if (delta < -max) {
    201 					delta= -max;
    202 					clamped= true;
    203 				}
    204 			}
    205 
    206 			int barLength= (int) (delta / max * w2);
    207 
    208 			if (delta < 0) {
    209 				if (bar.slowdownExpected != null) {
    210 					gc.setBackground(gray);
    211 				} else if (!bar.significant) {
    212 					gc.setBackground(yellow);
    213 				} else  {
    214 					gc.setBackground(red);
    215 				}
    216 			} else if (!bar.significant) {
    217 				gc.setBackground(yellow);
    218 			} else {
    219 				gc.setBackground(green);
    220 			}
    221 
    222 			if (barLength > 0) {
    223 				gc.fillRectangle(center, y + (GAP / 2), barLength, BARHEIGHT);
    224 				gc.drawRectangle(center, y + (GAP / 2), barLength, BARHEIGHT);
    225 			} else if (barLength < 0) {
    226 				gc.fillRectangle(center+barLength, y + (GAP / 2), -barLength, BARHEIGHT);
    227 				gc.drawRectangle(center+barLength, y + (GAP / 2), -barLength, BARHEIGHT);
    228 			}
    229 
    230 			if (clamped) {
    231 
    232 				int h2= (BARHEIGHT + GAP);
    233 				int x= center + barLength;
    234 				if (barLength > 0)
    235 					x-= FROM_END;
    236 				else
    237 					x+= FROM_END - GAP2 - SLANT;
    238 				int[] pts= new int[] { x, y + h2 - 1, x + SLANT, y + 1, x + SLANT + GAP2, y + 1, x + GAP2, y + h2 - 1};
    239 				if (i % 2 == 0)
    240 					gc.setBackground(lightblue);
    241 				else
    242 					gc.setBackground(white);
    243 				gc.fillPolygon(pts);
    244 				gc.drawLine(pts[0], pts[1], pts[2], pts[3]);
    245 				gc.drawLine(pts[4], pts[5], pts[6], pts[7]);
    246 			}
    247 
    248 			String label= nf.format(orgDelta);
    249 			Point labelExtent= gc.stringExtent(label);
    250 			int labelxpos= center + barLength;
    251 			int labelvpos= y + (BARHEIGHT + GAP - labelExtent.y) / 2;
    252 			if (orgDelta > 0.0) {
    253 				gc.drawString(label, labelxpos + TGAP, labelvpos, true);
    254 			} else {
    255 				gc.drawString(label, labelxpos - TGAP - labelExtent.x, labelvpos, true);
    256 			}
    257 
    258 			int x= MARGIN + w + TGAP;
    259 			String title= bar.title;
    260 			boolean hasURL= bar.url != null;
    261 			Color oldfg= gc.getForeground();
    262 			if (hasURL) {
    263 				gc.setForeground(blue);
    264 				Point e= gc.stringExtent(title);
    265 				gc.drawLine(x, labelvpos + e.y - 1, x + e.x, labelvpos + e.y - 1);
    266 			}
    267 			gc.drawString(title, x, labelvpos, true);
    268 			if (hasURL)
    269 				gc.setForeground(oldfg);
    270 
    271 			int y0= y;
    272 			y+= BARHEIGHT + GAP;
    273 
    274 			if (hasURL) {
    275 				if (this.fAreaBuffer == null)
    276 					this.fAreaBuffer= new StringBuffer();
    277 				this.fAreaBuffer.append("		echo '<area shape=\"RECT\" coords=\"0," + y0 + ',' + width + ',' + y + "\" href=\"" + bar.url + "\">';\n");
    278 			}
    279 		}
    280 
    281 		lightblue.dispose();
    282 		red.dispose();
    283 		green.dispose();
    284 	}
    285 
    286 	public String getAreas() {
    287 		if (this.fAreaBuffer != null) {
    288 			String s= this.fAreaBuffer.toString();
    289 			this.fAreaBuffer= null;
    290 			return s;
    291 		}
    292 		return null;
    293 	}
    294 }
    295