package hudson.plugins.violations.graph; import org.jfree.data.category.CategoryDataset; import hudson.util.DataSetBuilder; import hudson.util.ChartUtil.NumberOnlyBuildLabel; import hudson.plugins.violations.ViolationsReport; import hudson.plugins.violations.TypeSummary; import hudson.plugins.violations.model.Severity; import hudson.util.ShiftedCategoryAxis; import hudson.util.StackedAreaRenderer2; import java.awt.Color; import org.jfree.chart.renderer.category.StackedAreaRenderer; import org.jfree.chart.title.LegendTitle; import org.jfree.ui.RectangleEdge; import org.jfree.ui.RectangleInsets; import org.jfree.chart.ChartFactory; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.CategoryAxis; import org.jfree.chart.axis.CategoryLabelPositions; import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.plot.CategoryPlot; import org.jfree.chart.plot.PlotOrientation; /** * Class to construct a dataset for severities * of a particular type. */ public class SeverityTypeDataSet { // Some ikky colors private static final Color RED = new Color(0xEF, 0x29, 0x29); private static final Color VIOLET = new Color(0xEE, 0x82, 0xEE); private static final Color YELLOW = new Color(0xCC, 0xCC, 0x00); private static final Color GRAY = new Color(0x30, 0x30, 0x30); // Some constants private static final double INSET = 5.0; private static final float ALPHA = 0.8f; private final ViolationsReport report; private final String type; /** * Create a SeverityTypeData set from a report and a type. * @param report the current report. * @param type the type of violation to build from. */ public SeverityTypeDataSet(ViolationsReport report, String type) { this.report = report; this.type = type; } /** * Build the data set. * @return the dataset. */ public CategoryDataset buildDataSet() { DataSetBuilder<Row, NumberOnlyBuildLabel> builder = new DataSetBuilder<Row, NumberOnlyBuildLabel>(); for (ViolationsReport r = report; r != null; r = r.previous()) { if (r.getTypeSummaries() == null) { continue; } TypeSummary t = r.getTypeSummaries().get(type); if (t == null) { continue; // Old report } if (t.getSeverityArray() == null || t.getSeverityArray().length != Severity.NUMBER_SEVERITIES) { continue; // Old report } int[] nums = t.getSeverityArray(); builder.add( nums[Severity.MEDIUM_VALUE] + nums[Severity.MEDIUM_HIGH_VALUE] + nums[Severity.MEDIUM_LOW_VALUE], MEDIUM_ROW, new NumberOnlyBuildLabel(r.getBuild())); builder.add( nums[Severity.HIGH_VALUE], HIGH_ROW, new NumberOnlyBuildLabel(r.getBuild())); builder.add( nums[Severity.LOW_VALUE], LOW_ROW, new NumberOnlyBuildLabel(r.getBuild())); } return builder.build(); } /** * Create a JFree chart for this dataset. * @return the chart. */ public JFreeChart createChart() { CategoryDataset dataset = buildDataSet(); JFreeChart chart = ChartFactory.createStackedAreaChart( null, // chart title null, // unused "count", // range axis label dataset, // data PlotOrientation.VERTICAL, // orientation true, // include legend true, // tooltips false // urls ); // NOW DO SOME OPTIONAL CUSTOMISATION OF THE CHART... final LegendTitle legend = chart.getLegend(); legend.setPosition(RectangleEdge.RIGHT); chart.setBackgroundPaint(Color.white); final CategoryPlot plot = chart.getCategoryPlot(); plot.setBackgroundPaint(Color.WHITE); plot.setOutlinePaint(null); plot.setForegroundAlpha(ALPHA); plot.setRangeGridlinesVisible(true); plot.setRangeGridlinePaint(Color.black); CategoryAxis domainAxis = new ShiftedCategoryAxis(null); plot.setDomainAxis(domainAxis); domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_90); domainAxis.setLowerMargin(0.0); domainAxis.setUpperMargin(0.0); domainAxis.setCategoryMargin(0.0); final NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis(); rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits()); StackedAreaRenderer renderer = new StackedAreaRenderer2(); plot.setRenderer(renderer); renderer.setSeriesPaint(2, RED); renderer.setSeriesPaint(1, VIOLET); renderer.setSeriesPaint(0, YELLOW); // crop extra space around the graph plot.setInsets(new RectangleInsets(0, 0, 0, INSET)); return chart; } private static class Row implements Comparable<Row> { private final String tag; private final int number; public Row(String tag, int number) { this.tag = tag; this.number = number; } public String toString() { return tag; } public int compareTo(Row other) { return number == other.number ? 0 : number < other.number ? 1 : -1; } } private static final Row HIGH_ROW = new Row(Severity.HIGH, 0); private static final Row MEDIUM_ROW = new Row(Severity.MEDIUM, 1); private static final Row LOW_ROW = new Row(Severity.LOW, 2); }