| /******************************************************************************* |
| * Copyright (c) 2000, 2009 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.test.performance.ui; |
| |
| import java.text.NumberFormat; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.graphics.Color; |
| import org.eclipse.swt.graphics.GC; |
| import org.eclipse.swt.graphics.Point; |
| import org.eclipse.swt.widgets.Display; |
| |
| public class BarGraph { |
| |
| private static final int MARGIN= 5; // margin on all four sides |
| private static final int BARHEIGHT= 8; // height of bar |
| private static final int GAP= 10; // gap between bars |
| private static final int TGAP= 5; // gap between lines and labels |
| |
| private static final boolean NO_SCALE= true; // |
| |
| // if NO_SCALE is true the following values are used: |
| private static final double RATIO= 0.6; // fraction of width reserved for bar graph; needs tweaking |
| private static final int FROM_END= 20; // a break (//) is shown this far from end of bar |
| private static final int SLANT= 8; // slant of break |
| private static final int GAP2= 5; // width of break |
| |
| private StringBuffer fAreaBuffer; |
| |
| private static class BarItem { |
| |
| String title; |
| double value; |
| String url; |
| String slowdownExpected; |
| boolean significant; |
| |
| BarItem(String t, double[] stats, String u, String slow, boolean sig) { |
| this.title= t; |
| this.value= stats[0]==0 ? 0 : -stats[0] * 100; |
| this.url= u; |
| this.slowdownExpected= slow; |
| this.significant= sig; |
| } |
| } |
| |
| private String fTitle; |
| private List fItems; |
| |
| BarGraph(String title) { |
| this.fTitle= title; |
| this.fItems= new ArrayList(); |
| } |
| |
| public void addItem(String name, double[] stats, String url, String slow, boolean significant) { |
| this.fItems.add(new BarItem(name, stats, url, slow, significant)); |
| } |
| |
| public int getHeight() { |
| int n= this.fItems.size(); |
| int textHeight= 16; |
| int titleHeight= 0; |
| if (this.fTitle != null) |
| titleHeight= textHeight + GAP; |
| return MARGIN + titleHeight + n * (GAP + BARHEIGHT) + GAP + textHeight + MARGIN; |
| } |
| |
| public void paint(Display display, int width, int height, GC gc) { |
| |
| NumberFormat nf= NumberFormat.getInstance(); |
| |
| BarItem[] bars= (BarItem[]) this.fItems.toArray(new BarItem[this.fItems.size()]); |
| |
| // draw white background |
| Color bg= display.getSystemColor(SWT.COLOR_WHITE); |
| gc.setBackground(bg); |
| gc.fillRectangle(0, 0, width, height); |
| |
| // determine the widths of the bar and the label areas |
| int w; |
| if (NO_SCALE) { |
| // we use a fixed width |
| w= (int) (RATIO * width); |
| } else { |
| // we calculate the max width |
| int maxNameLength= 0; |
| for (int i= 0; i < bars.length; i++) { |
| Point es= gc.stringExtent(bars[i].title); |
| maxNameLength= Math.max(maxNameLength, es.x); |
| } |
| w= width - maxNameLength - TGAP - 2 * MARGIN; |
| } |
| |
| Color fg= display.getSystemColor(SWT.COLOR_BLACK); |
| |
| int vstart= 0; // start rows here |
| if (this.fTitle != null) { |
| vstart= gc.stringExtent(this.fTitle).y + GAP; |
| gc.drawString(this.fTitle, MARGIN, MARGIN, true); // draw title left aligned |
| } |
| |
| int center= MARGIN + w / 2; |
| int w2= w / 2 - gc.stringExtent("-999.9").x - TGAP; // reserve space //$NON-NLS-1$ |
| |
| // determine maximum of values |
| double max= 0.0; |
| for (int i= 0; i < bars.length; i++) |
| max= Math.max(max, Math.abs(bars[i].value)); |
| |
| double d; |
| if (NO_SCALE) { |
| d= 25; |
| max= 125; |
| } else { |
| if (max > 400.0) { |
| d= 200; |
| } else if (max > 200.0) { |
| d= 100; |
| } else if (max > 100.0) { |
| d= 50; |
| } else if (max > 50) { |
| d= 25; |
| } else if (max > 25) { |
| d= 10; |
| } else if (max > 10) { |
| d= 5; |
| } else if (max > 5) { |
| d= 2.5; |
| } else { |
| d= 1.0; |
| } |
| } |
| |
| // draw striped background |
| int y= MARGIN + vstart; |
| Color lightblue= new Color(display, 237, 243, 254); |
| gc.setBackground(lightblue); |
| for (int i= 0; i < bars.length; i++) |
| if (i % 2 == 0) |
| gc.fillRectangle(0, y + i * (BARHEIGHT + GAP), width, BARHEIGHT + GAP); |
| |
| // draw grid |
| int yy= y + bars.length * (BARHEIGHT + GAP); |
| gc.drawLine(center, y, center, yy + TGAP); |
| Color grey= display.getSystemColor(SWT.COLOR_GRAY); |
| for (int i= 1; d * i < max; i++) { |
| |
| double xx= d * i; |
| int x= (int) ((xx / max) * w2); |
| |
| gc.setForeground(grey); |
| gc.drawLine(center - x, y, center - x, yy + TGAP); |
| gc.drawLine(center + x, y, center + x, yy + TGAP); |
| |
| gc.setForeground(fg); |
| |
| String s3= nf.format(-xx) + "%"; //$NON-NLS-1$ |
| Point es3= gc.stringExtent(s3); |
| gc.drawString(s3, center - x - es3.x / 2, yy + TGAP, true); |
| |
| String s4= nf.format(xx) + "%"; //$NON-NLS-1$ |
| Point es4= gc.stringExtent(s4); |
| gc.drawString(s4, center + x - es4.x / 2, yy + TGAP, true); |
| } |
| gc.drawLine(0, yy, w, yy); |
| |
| nf.setMaximumFractionDigits(1); |
| |
| // link color |
| Color blue= display.getSystemColor(SWT.COLOR_BLUE); |
| // draw bars |
| // Color green= display.getSystemColor(SWT.COLOR_GREEN); |
| // Color red= display.getSystemColor(SWT.COLOR_RED); |
| Color green = new Color(display, 95, 191, 95); |
| Color red = new Color(display, 225, 50, 50); |
| Color gray= display.getSystemColor(SWT.COLOR_GRAY); |
| Color yellow= display.getSystemColor(SWT.COLOR_YELLOW); |
| Color white= display.getSystemColor(SWT.COLOR_WHITE); |
| for (int i= 0; i < bars.length; i++) { |
| |
| BarItem bar= bars[i]; |
| double delta = bar.value; |
| double orgDelta= delta; |
| |
| boolean clamped= false; |
| if (NO_SCALE) { |
| if (delta > max) { |
| delta= max; |
| clamped= true; |
| } else if (delta < -max) { |
| delta= -max; |
| clamped= true; |
| } |
| } |
| |
| int barLength= (int) (delta / max * w2); |
| |
| if (delta < 0) { |
| if (bar.slowdownExpected != null) { |
| gc.setBackground(gray); |
| } else if (!bar.significant) { |
| gc.setBackground(yellow); |
| } else { |
| gc.setBackground(red); |
| } |
| } else if (!bar.significant) { |
| gc.setBackground(yellow); |
| } else { |
| gc.setBackground(green); |
| } |
| |
| if (barLength > 0) { |
| gc.fillRectangle(center, y + (GAP / 2), barLength, BARHEIGHT); |
| gc.drawRectangle(center, y + (GAP / 2), barLength, BARHEIGHT); |
| } else if (barLength < 0) { |
| gc.fillRectangle(center+barLength, y + (GAP / 2), -barLength, BARHEIGHT); |
| gc.drawRectangle(center+barLength, y + (GAP / 2), -barLength, BARHEIGHT); |
| } |
| |
| if (clamped) { |
| |
| int h2= (BARHEIGHT + GAP); |
| int x= center + barLength; |
| if (barLength > 0) |
| x-= FROM_END; |
| else |
| x+= FROM_END - GAP2 - SLANT; |
| int[] pts= new int[] { x, y + h2 - 1, x + SLANT, y + 1, x + SLANT + GAP2, y + 1, x + GAP2, y + h2 - 1}; |
| if (i % 2 == 0) |
| gc.setBackground(lightblue); |
| else |
| gc.setBackground(white); |
| gc.fillPolygon(pts); |
| gc.drawLine(pts[0], pts[1], pts[2], pts[3]); |
| gc.drawLine(pts[4], pts[5], pts[6], pts[7]); |
| } |
| |
| String label= nf.format(orgDelta); |
| Point labelExtent= gc.stringExtent(label); |
| int labelxpos= center + barLength; |
| int labelvpos= y + (BARHEIGHT + GAP - labelExtent.y) / 2; |
| if (orgDelta > 0.0) { |
| gc.drawString(label, labelxpos + TGAP, labelvpos, true); |
| } else { |
| gc.drawString(label, labelxpos - TGAP - labelExtent.x, labelvpos, true); |
| } |
| |
| int x= MARGIN + w + TGAP; |
| String title= bar.title; |
| boolean hasURL= bar.url != null; |
| Color oldfg= gc.getForeground(); |
| if (hasURL) { |
| gc.setForeground(blue); |
| Point e= gc.stringExtent(title); |
| gc.drawLine(x, labelvpos + e.y - 1, x + e.x, labelvpos + e.y - 1); |
| } |
| gc.drawString(title, x, labelvpos, true); |
| if (hasURL) |
| gc.setForeground(oldfg); |
| |
| int y0= y; |
| y+= BARHEIGHT + GAP; |
| |
| if (hasURL) { |
| if (this.fAreaBuffer == null) |
| this.fAreaBuffer= new StringBuffer(); |
| this.fAreaBuffer.append(" echo '<area shape=\"RECT\" coords=\"0," + y0 + ',' + width + ',' + y + "\" href=\"" + bar.url + "\">';\n"); |
| } |
| } |
| |
| lightblue.dispose(); |
| red.dispose(); |
| green.dispose(); |
| } |
| |
| public String getAreas() { |
| if (this.fAreaBuffer != null) { |
| String s= this.fAreaBuffer.toString(); |
| this.fAreaBuffer= null; |
| return s; |
| } |
| return null; |
| } |
| } |