| /******************************************************************************* |
| * 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.io.File; |
| import java.io.PrintStream; |
| import java.text.NumberFormat; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.graphics.Color; |
| import org.eclipse.swt.graphics.Font; |
| import org.eclipse.swt.graphics.FontData; |
| import org.eclipse.swt.graphics.GC; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.swt.graphics.ImageData; |
| import org.eclipse.swt.graphics.Point; |
| import org.eclipse.swt.graphics.Rectangle; |
| import org.eclipse.swt.graphics.Resource; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.test.internal.performance.results.db.BuildResults; |
| import org.eclipse.test.internal.performance.results.db.ConfigResults; |
| import org.eclipse.test.internal.performance.results.db.DB_Results; |
| import org.eclipse.test.internal.performance.results.db.ScenarioResults; |
| import org.eclipse.test.internal.performance.results.utils.Util; |
| |
| /** |
| * Abstract class to build graph with bars |
| */ |
| public class FingerPrintGraph { |
| |
| // Sizes |
| static final int MARGIN= 5; // margin on all four sides |
| static final int BAR_HEIGHT= 6; // height of bar |
| static final int GAP= 10; // gap between bars |
| static final int TGAP= 5; // gap between lines and labels |
| static final int LINE_HEIGHT = 2*BAR_HEIGHT + GAP; |
| |
| // fraction of width reserved for bar graph |
| static final double RATIO= 0.6; |
| |
| // Formatting constants |
| static final NumberFormat NUMBER_FORMAT; |
| static { |
| NUMBER_FORMAT = NumberFormat.getInstance(); |
| NUMBER_FORMAT.setMaximumFractionDigits(1); |
| } |
| |
| // Graphic constants |
| static final Display DEFAULT_DISPLAY = Display.getDefault(); |
| static final Color BLACK= DEFAULT_DISPLAY.getSystemColor(SWT.COLOR_BLACK); |
| static final Color BLUE= DEFAULT_DISPLAY.getSystemColor(SWT.COLOR_BLUE); |
| static final Color GREEN= DEFAULT_DISPLAY.getSystemColor(SWT.COLOR_GREEN); |
| static final Color RED = DEFAULT_DISPLAY.getSystemColor(SWT.COLOR_RED); |
| static final Color GRAY = DEFAULT_DISPLAY.getSystemColor(SWT.COLOR_GRAY); |
| static final Color DARK_GRAY = DEFAULT_DISPLAY.getSystemColor(SWT.COLOR_DARK_GRAY); |
| static final Color YELLOW = DEFAULT_DISPLAY.getSystemColor(SWT.COLOR_YELLOW); |
| static final Color WHITE = DEFAULT_DISPLAY.getSystemColor(SWT.COLOR_WHITE); |
| |
| // Bar graph kinds |
| static final int NO_TIME = 0; // i.e. percentage |
| static final int TIME_LINEAR = 1; |
| static final int TIME_LOG = 2; |
| static final int[] SUPPORTED_GRAPHS = { |
| // NO_TIME, |
| TIME_LINEAR, |
| TIME_LOG, |
| }; |
| |
| // Graphic fields |
| GC gc; |
| Image image; |
| int imageWidth; |
| int imageHeight; |
| int graphWidth; |
| int graphHeight; |
| Map resources = new HashMap(); |
| |
| // Data fields |
| int count = 0; |
| ConfigResults[] results = new ConfigResults[10]; |
| BarGraphArea[] areas; |
| |
| // Values |
| double maxValue = 0.0; |
| double minValue = Double.MAX_VALUE; |
| |
| // File info |
| File outputDir; |
| String imageName; |
| private final String defaultDimName = DB_Results.getDefaultDimension().getName(); |
| |
| /* |
| * Member class defining a bar graph area. |
| * This area applies to a configuration results and is made of several zones. |
| */ |
| class BarGraphArea { |
| List zones; |
| private ConfigResults configResults; |
| |
| /* |
| * Member class defining a zone inside a bar graph area. |
| * Typically made of a rectangle and an associated text used as tooltip. |
| */ |
| class AreaZone { |
| Rectangle zone; |
| String title; |
| |
| AreaZone(Rectangle zone, String tooltip) { |
| super(); |
| this.zone = zone; |
| this.title = tooltip; |
| } |
| |
| void print(String url, PrintStream stream) { |
| stream.print(" echo '<area shape=\"RECT\""); |
| if (this.title != null) { |
| stream.print(" title=\""+this.title+"\""); |
| } |
| stream.print("coords=\""); |
| stream.print(this.zone.x); |
| stream.print(','); |
| stream.print(this.zone.y); |
| stream.print(','); |
| stream.print(this.zone.x+this.zone.width); |
| stream.print(','); |
| stream.print(this.zone.y+this.zone.height); |
| stream.print('"'); |
| if (url != null) { |
| stream.print(" href=\""); |
| stream.print(url); |
| stream.print('"'); |
| } |
| stream.print(">';\n"); |
| } |
| } |
| |
| BarGraphArea(ConfigResults results) { |
| this.configResults = results; |
| this.zones = new ArrayList(); |
| } |
| |
| void print(PrintStream stream) { |
| String url = this.configResults.getName() + "/" + ((ScenarioResults) this.configResults.getParent()).getFileName() + ".html"; |
| int size = this.zones.size(); |
| for (int i=0; i<size; i++) { |
| AreaZone zone = (AreaZone) this.zones.get(i); |
| zone.print(url, stream); |
| } |
| } |
| |
| void addArea(Rectangle rec, String tooltip) { |
| AreaZone zone = new AreaZone(rec, tooltip); |
| this.zones.add(zone); |
| } |
| |
| } |
| |
| |
| FingerPrintGraph(File dir, String fileName, int width, List results) { |
| super(); |
| this.imageWidth = width; |
| this.count = results.size(); |
| this.results = new ConfigResults[this.count]; |
| results.toArray(this.results); |
| this.outputDir = dir; |
| this.imageName = fileName; |
| } |
| |
| /** |
| */ |
| void drawBars(int kind) { |
| |
| // Get/Set graphical resources |
| Font italicFont = (Font) this.resources.get("italicFont"); |
| if (italicFont == null) { |
| String fontDataName = this.gc.getFont().getFontData()[0].toString(); |
| FontData fdItalic = new FontData(fontDataName); |
| fdItalic.setStyle(SWT.ITALIC); |
| italicFont = new Font(DEFAULT_DISPLAY, fdItalic); |
| this.resources.put("italicFont", italicFont); |
| } |
| Color blueref = (Color) this.resources.get("blueref"); |
| if (blueref == null) { |
| blueref = new Color(DEFAULT_DISPLAY, 200, 200, 255); |
| this.resources.put("blueref", blueref); |
| } |
| Color lightyellow= (Color) this.resources.get("lightyellow"); |
| if (lightyellow == null) { |
| lightyellow = new Color(DEFAULT_DISPLAY, 255, 255, 160); |
| this.resources.put("lightyellow", lightyellow); |
| } |
| Color darkyellow= (Color) this.resources.get("darkyellow"); |
| if (darkyellow == null) { |
| darkyellow = new Color(DEFAULT_DISPLAY, 160, 160, 0); |
| this.resources.put("darkyellow", darkyellow); |
| } |
| Color okColor= (Color) this.resources.get("lightgreen"); |
| if (okColor == null) { |
| okColor = new Color(DEFAULT_DISPLAY, 95, 191, 95); |
| this.resources.put("lightgreen", okColor); |
| } |
| Color failureColor = (Color) this.resources.get("lightred"); |
| if (failureColor == null) { |
| failureColor = new Color(DEFAULT_DISPLAY, 220, 50, 50); |
| this.resources.put("lightred", failureColor); |
| } |
| |
| // Build each scenario bar graph |
| this.areas = new BarGraphArea[this.count]; |
| double max = kind == TIME_LOG ? Math.log(this.maxValue) : this.maxValue; |
| for (int i=0, y=MARGIN; i < this.count; i++, y+=LINE_HEIGHT) { |
| |
| // get builds info |
| ConfigResults configResults = this.results[i]; |
| this.areas[i] = new BarGraphArea(configResults); |
| BarGraphArea graphArea = this.areas[i]; |
| BuildResults currentBuildResults = configResults.getCurrentBuildResults(); |
| double currentValue = currentBuildResults.getValue(); |
| double currentError = currentBuildResults.getError(); |
| double error = configResults.getError(); |
| boolean singleTest = Double.isNaN(error); |
| boolean isSignificant = singleTest || error < Utils.STANDARD_ERROR_THRESHOLD; |
| boolean isCommented = currentBuildResults.getComment() != null; |
| BuildResults baselineBuildResults = configResults.getBaselineBuildResults(); |
| double baselineValue = baselineBuildResults.getValue(); |
| double baselineError = baselineBuildResults.getError(); |
| |
| // draw baseline build bar |
| Color whiteref = (Color) this.resources.get("whiteref"); |
| if (whiteref == null) { |
| whiteref = new Color(DEFAULT_DISPLAY, 240, 240, 248); |
| this.resources.put("whiteref", whiteref); |
| } |
| this.gc.setBackground(whiteref); |
| double baselineGraphValue = kind == TIME_LOG ? Math.log(baselineValue) : baselineValue; |
| int baselineBarLength= (int) (baselineGraphValue / max * this.graphWidth); |
| int baselineErrorLength= (int) (baselineError / max * this.graphWidth / 2); |
| int labelxpos = MARGIN + baselineBarLength; |
| if (kind == TIME_LOG || baselineErrorLength <= 1) { |
| this.gc.fillRectangle(MARGIN, y + (GAP/2), baselineBarLength, BAR_HEIGHT); |
| Rectangle rec = new Rectangle(MARGIN, y + (GAP/2), baselineBarLength, BAR_HEIGHT); |
| this.gc.drawRectangle(rec); |
| graphArea.addArea(rec, "Time for baseline build "+baselineBuildResults.getName()+": "+Util.timeString((long)baselineValue)); |
| } else { |
| int wr = baselineBarLength - baselineErrorLength; |
| Rectangle recValue = new Rectangle(MARGIN, y + (GAP/2), wr, BAR_HEIGHT); |
| this.gc.fillRectangle(recValue); |
| this.gc.setBackground(YELLOW); |
| Rectangle recError = new Rectangle(MARGIN+wr, y + (GAP/2), baselineErrorLength*2, BAR_HEIGHT); |
| this.gc.fillRectangle(recError); |
| Rectangle rec = new Rectangle(MARGIN, y + (GAP/2), baselineBarLength+baselineErrorLength, BAR_HEIGHT); |
| this.gc.drawRectangle(rec); |
| StringBuffer tooltip = new StringBuffer("Time for baseline build "); |
| tooltip.append(baselineBuildResults.getName()); |
| tooltip.append(": "); |
| tooltip.append(Util.timeString((long)baselineValue)); |
| tooltip.append(" [±"); |
| tooltip.append(Util.timeString((long)baselineError)); |
| tooltip.append(']'); |
| graphArea.addArea(rec, tooltip.toString()); |
| labelxpos += baselineErrorLength; |
| } |
| |
| // set current build bar color |
| if (baselineValue < currentValue) { |
| if (isCommented) { |
| this.gc.setBackground(GRAY); |
| } else { |
| this.gc.setBackground(failureColor); |
| } |
| } else { |
| this.gc.setBackground(okColor); |
| } |
| |
| // draw current build bar |
| double currentGraphValue = kind == TIME_LOG ? Math.log(currentValue) : currentValue; |
| int currentBarLength= (int) (currentGraphValue / max * this.graphWidth); |
| int currentErrorLength= (int) (currentError / max * this.graphWidth / 2); |
| if (kind == TIME_LOG || currentErrorLength <= 1) { |
| this.gc.fillRectangle(MARGIN, y + (GAP/2) + BAR_HEIGHT, currentBarLength, BAR_HEIGHT); |
| Rectangle rec = new Rectangle(MARGIN, y + (GAP/2) + BAR_HEIGHT, currentBarLength, BAR_HEIGHT); |
| this.gc.drawRectangle(rec); |
| String tooltip = "Time for current build "+currentBuildResults.getName()+": "+Util.timeString((long)currentValue); |
| if (isCommented) { |
| tooltip += ". " + currentBuildResults.getComment(); |
| } |
| graphArea.addArea(rec, tooltip); |
| if (labelxpos < (MARGIN+currentBarLength)) { |
| labelxpos = MARGIN + currentBarLength; |
| } |
| } else { |
| int wr = currentBarLength - currentErrorLength; |
| Rectangle recValue = new Rectangle(MARGIN, y + (GAP/2) + BAR_HEIGHT, wr, BAR_HEIGHT); |
| this.gc.fillRectangle(recValue); |
| this.gc.setBackground(YELLOW); |
| Rectangle recError = new Rectangle(MARGIN+wr, y + (GAP/2) + BAR_HEIGHT, currentErrorLength*2, BAR_HEIGHT); |
| this.gc.fillRectangle(recError); |
| Rectangle rec = new Rectangle(MARGIN, y + (GAP/2) + BAR_HEIGHT, currentBarLength+currentErrorLength, BAR_HEIGHT); |
| this.gc.drawRectangle(rec); |
| StringBuffer tooltip = new StringBuffer("Time for current build "); |
| tooltip.append(currentBuildResults.getName()); |
| tooltip.append(": "); |
| tooltip.append(Util.timeString((long)currentValue)); |
| tooltip.append(" [±"); |
| tooltip.append(Util.timeString((long)currentError)); |
| tooltip.append(']'); |
| if (isCommented) { |
| tooltip.append(". "); |
| tooltip.append(currentBuildResults.getComment()); |
| } |
| graphArea.addArea(rec, tooltip.toString()); |
| if (labelxpos < (MARGIN+currentBarLength+currentErrorLength)) { |
| labelxpos = MARGIN + currentBarLength+currentErrorLength; |
| } |
| } |
| |
| // set delta value style and color |
| boolean hasFailure = currentBuildResults.getFailure() != null; |
| if (hasFailure) { |
| if (isCommented) { |
| this.gc.setForeground(DARK_GRAY); |
| } else { |
| this.gc.setForeground(RED); |
| } |
| } else { |
| this.gc.setForeground(BLACK); |
| } |
| |
| // draw delta value |
| double delta = -configResults.getDelta(); |
| String label = delta > 0 ? "+" : ""; |
| label += NUMBER_FORMAT.format(delta*100) + "%"; |
| Point labelExtent= this.gc.stringExtent(label); |
| int labelvpos= y + (LINE_HEIGHT - labelExtent.y) / 2; |
| this.gc.drawString(label, labelxpos+TGAP, labelvpos, true); |
| this.gc.setForeground(BLACK); |
| this.gc.setFont(null); |
| int titleStart = (int) (RATIO * this.imageWidth); |
| if (singleTest || !isSignificant) { |
| String deltaTooltip = null; |
| if (singleTest) { |
| deltaTooltip = "This test performed only one iteration; hence its reliability cannot be assessed"; |
| } else if (!isSignificant) { |
| deltaTooltip = "This test has a bad reliability: error is "+NUMBER_FORMAT.format(error*100)+"% (> 3%)!"; |
| } |
| Image warning = (Image) this.resources.get("warning"); |
| int xi = labelxpos+TGAP+labelExtent.x; |
| this.gc.drawImage(warning, xi, labelvpos); |
| ImageData imageData = warning.getImageData(); |
| // Set zones |
| // - first one is between end of bar and warning image beginning |
| Rectangle deltaZone = new Rectangle(labelxpos, labelvpos-2, xi-labelxpos, labelExtent.y+4); |
| graphArea.addArea(deltaZone, null); |
| // - second one is the warning image |
| Rectangle warningZone = new Rectangle(xi, labelvpos, imageData.width, imageData.height); |
| graphArea.addArea(warningZone, deltaTooltip); |
| // - last one is between end of the warning image and the scenario title beginning |
| int warningImageEnd = xi+imageData.width; |
| Rectangle emptyZone = new Rectangle(warningImageEnd, labelvpos, titleStart-warningImageEnd, imageData.height); |
| graphArea.addArea(emptyZone, deltaTooltip); |
| } else { |
| // No tooltip => delta zone is between end of bar and the scenario title beginning |
| Rectangle deltaZone = new Rectangle(labelxpos, labelvpos-2, titleStart-labelxpos, labelExtent.y+4); |
| graphArea.addArea(deltaZone, null); |
| } |
| |
| // set title style |
| Color oldfg= this.gc.getForeground(); |
| this.gc.setForeground(BLUE); |
| |
| // draw scenario title |
| int x= titleStart; |
| ScenarioResults scenarioResults = (ScenarioResults) configResults.getParent(); |
| String title = scenarioResults.getLabel() + " (" + this.defaultDimName + ")"; |
| Point e= this.gc.stringExtent(title); |
| this.gc.drawLine(x, labelvpos + e.y - 1, x + e.x, labelvpos + e.y - 1); |
| this.gc.drawString(title, x, labelvpos, true); |
| this.gc.setForeground(oldfg); |
| this.gc.setFont(null); |
| Rectangle titleZone = new Rectangle(x, labelvpos, e.x, e.y); |
| graphArea.addArea(titleZone, null/*no tooltip*/); |
| if (!configResults.isBaselined()) { |
| Image warning = (Image) this.resources.get("warning"); |
| this.gc.drawImage(warning, x+e.x, labelvpos); |
| ImageData imageData = warning.getImageData(); |
| Rectangle warningZone = new Rectangle(x+e.x, labelvpos, imageData.width, imageData.height); |
| String titleTooltip = "This test has no baseline result, hence use build "+configResults.getBaselineBuildName()+" for reference!"; |
| graphArea.addArea(warningZone, titleTooltip); |
| } |
| } |
| } |
| |
| void drawLinearScale() { |
| |
| // Draw scale background |
| drawScaleBackground(); |
| |
| // Draw scale grid lines |
| int gridValue = 100; |
| int n = (int) (this.maxValue / gridValue); |
| while (n > 10) { |
| switch (gridValue) { |
| case 100: |
| gridValue = 200; |
| break; |
| case 200: |
| gridValue = 500; |
| break; |
| case 500: |
| gridValue = 1000; |
| break; |
| default: |
| gridValue += 1000; |
| break; |
| } |
| n = (int) (this.maxValue / gridValue); |
| } |
| int gridWidth = (int) (this.graphWidth * gridValue / this.maxValue); |
| int x = MARGIN; |
| long value = 0; // TODO use minValue instead |
| while (x < this.graphWidth) { |
| |
| // draw line |
| this.gc.setForeground(GRAY); |
| if (x > 0) { |
| this.gc.setLineStyle(SWT.LINE_DOT); |
| this.gc.drawLine(x, MARGIN, x, this.graphHeight + TGAP); |
| } |
| |
| // draw value |
| this.gc.setForeground(BLACK); |
| String val= Util.timeString(value); |
| Point point= this.gc.stringExtent(val); |
| this.gc.drawString(val, x - point.x / 2, this.graphHeight + TGAP, true); |
| |
| // compute next grid position |
| x += gridWidth; |
| value += gridValue; // value is expressed in seconds |
| } |
| this.gc.setLineStyle(SWT.LINE_SOLID); |
| this.gc.drawLine(0, this.graphHeight, this.graphWidth, this.graphHeight); |
| } |
| |
| void drawLogarithmScale() { |
| |
| // Draw scale background |
| drawScaleBackground(); |
| |
| // Draw scale grid lines |
| double max = Math.log(this.maxValue); |
| int gridValue = 100; |
| int x = MARGIN; |
| long value = 0; // TODO use minValue instead |
| while (x < this.graphWidth) { |
| |
| // draw line |
| this.gc.setForeground(GRAY); |
| if (x > MARGIN) { |
| this.gc.setLineStyle(SWT.LINE_DOT); |
| this.gc.drawLine(x, MARGIN, x, this.graphHeight + TGAP); |
| } |
| |
| // draw value |
| this.gc.setForeground(BLACK); |
| String str = Util.timeString(value); |
| Point point= this.gc.stringExtent(str); |
| this.gc.drawString(str, x - point.x / 2, this.graphHeight + TGAP, true); |
| |
| // compute next grid position |
| value += gridValue; |
| int v = (int) (value / 100); |
| int c = 1; |
| while (v > 10) { |
| v = v / 10; |
| c *= 10; |
| } |
| switch (v) { |
| case 3: |
| gridValue = 200*c; |
| break; |
| case 5: |
| gridValue = 500*c; |
| break; |
| case 10: |
| gridValue = 1000*c; |
| break; |
| } |
| x = MARGIN + (int) (this.graphWidth * Math.log(value) / max); |
| } |
| this.gc.setLineStyle(SWT.LINE_SOLID); |
| this.gc.drawLine(0, this.graphHeight, this.graphWidth, this.graphHeight); |
| } |
| |
| /** |
| * Draw the scale depending on the bar time graph kind. |
| */ |
| void drawScale(int kind) { |
| switch (kind) { |
| case TIME_LINEAR: |
| drawLinearScale(); |
| break; |
| case TIME_LOG: |
| drawLogarithmScale(); |
| break; |
| } |
| } |
| |
| private void drawScaleBackground() { |
| |
| // Draw striped background |
| Color lightblue = (Color) this.resources.get("lightblue"); |
| if (lightblue == null) { |
| lightblue = new Color(DEFAULT_DISPLAY, 237, 243, 254); |
| this.resources.put("lightblue", lightblue); |
| } |
| this.gc.setBackground(lightblue); |
| for (int i= 0; i<this.count; i++) { |
| if (i % 2 == 0) { |
| this.gc.fillRectangle(0, MARGIN + i * LINE_HEIGHT, this.imageWidth, LINE_HEIGHT); |
| } |
| } |
| |
| // Draw bottom vertical line |
| int yy= MARGIN + this.count * LINE_HEIGHT; |
| this.gc.drawLine(MARGIN, MARGIN, MARGIN, yy + TGAP); |
| } |
| |
| String getImageName(int kind) { |
| switch (kind) { |
| case TIME_LINEAR: |
| return this.imageName+"_linear"; |
| case TIME_LOG: |
| return this.imageName+"_log"; |
| } |
| return this.imageName; |
| } |
| |
| void paint(int kind) { |
| |
| // Set image |
| this.graphHeight = MARGIN + this.count * LINE_HEIGHT; |
| this.imageHeight = this.graphHeight + GAP + 16 + MARGIN; |
| this.image = new Image(DEFAULT_DISPLAY, this.imageWidth, this.imageHeight); |
| this.gc = new GC(this.image); |
| |
| // draw white background |
| this.gc.setBackground(WHITE); |
| this.gc.fillRectangle(0, 0, this.imageWidth, this.imageHeight); |
| |
| // Set widths and heights |
| int width= (int) (RATIO * this.imageWidth); // width for results bar |
| this.graphWidth= width - this.gc.stringExtent("-999.9%").x - TGAP - MARGIN; // reserve space //$NON-NLS-1$ |
| |
| // Get warning image width |
| Image warning = (Image) this.resources.get("warning"); |
| if (warning == null) { |
| warning = new Image(this.gc.getDevice(), new File(this.outputDir, Utils.WARNING_OBJ).toString()); |
| this.resources.put("warning", warning); |
| } |
| this.graphWidth -= warning.getImageData().width; |
| |
| // Set maximum of values |
| this.maxValue = 0.0; |
| this.minValue = Double.MAX_VALUE; |
| for (int i= 0; i<this.count; i++) { |
| BuildResults baselineBuildResults = this.results[i].getBaselineBuildResults(); |
| double value = baselineBuildResults.getValue(); |
| double error = baselineBuildResults.getError(); |
| if (!Double.isNaN(error)) value += Math.abs(error); |
| if (value < 1000000 && value > this.maxValue) { |
| this.maxValue = value; |
| } |
| if (value < this.minValue) { |
| this.minValue = value; |
| } |
| BuildResults currentBuildResults = this.results[i].getCurrentBuildResults(); |
| value = currentBuildResults.getValue(); |
| error = currentBuildResults.getError(); |
| if (!Double.isNaN(error)) value += Math.abs(error); |
| if (value < 1000000 && value > this.maxValue) { |
| this.maxValue = value; |
| } |
| if (value < this.minValue) { |
| this.minValue = value; |
| } |
| } |
| this.minValue = 0; // do not use minValue for now... |
| |
| // Draw the scale |
| drawScale(kind); |
| |
| // Draw the bars |
| drawBars(kind); |
| |
| // Dispose |
| this.gc.dispose(); |
| } |
| |
| /** |
| * Create, paint and save all supported bar graphs and add the corresponding |
| * image and map references in the given stream. |
| * |
| * @param stream |
| */ |
| final public void paint(PrintStream stream) { |
| |
| // Paint supported graphs |
| int length = SUPPORTED_GRAPHS.length; |
| for (int i=0; i<length; i++) { |
| int kind = SUPPORTED_GRAPHS[i]; |
| paint(kind); |
| save(kind, stream); |
| } |
| |
| // Dispose created graphic resources |
| Iterator iterator = this.resources.values().iterator(); |
| while (iterator.hasNext()) { |
| Resource resource = (Resource) iterator.next(); |
| resource.dispose(); |
| } |
| this.resources.clear(); |
| } |
| |
| void print(int kind, PrintStream stream) { |
| String imgName = getImageName(kind); |
| stream.print(" if ($type==\"fp_type="+kind+"\") {\n"); |
| stream.print(" echo '<img src=\""); |
| stream.print(imgName); |
| stream.print(".gif\" usemap=\"#"); |
| stream.print(imgName); |
| stream.print("\" name=\""); |
| stream.print(imgName.substring(imgName.lastIndexOf('.'))); |
| stream.print("\">';\n"); |
| stream.print(" echo '<map name=\""); |
| stream.print(imgName); |
| stream.print("\">';\n"); |
| if (this.areas != null) { |
| for (int i=0; i<this.count; i++) { |
| this.areas[i].print(stream); |
| } |
| } |
| stream.print(" echo '</map>';\n"); |
| stream.print(" }\n"); |
| } |
| |
| void save(int kind, PrintStream stream) { |
| File file = new File(this.outputDir, getImageName(kind)+".gif"); |
| Utils.saveImage(file, this.image); |
| if (file.exists()) { |
| print(kind, stream); |
| } else { |
| stream.print("<br><br>There is no fingerprint for "); |
| stream.print(this.imageName); |
| stream.print(" (kind="); |
| stream.print(kind); |
| stream.print(")<br><br>\n"); |
| } |
| } |
| } |