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