package hudson.plugins.helpers;
import hudson.model.AbstractBuild;
import hudson.plugins.cppncss.AbstractBuildReport;
import hudson.plugins.cppncss.parser.Statistic;
import hudson.util.ChartUtil;
import hudson.util.DataSetBuilder;
import hudson.util.ShiftedCategoryAxis;
import hudson.util.ChartUtil.NumberOnlyBuildLabel;
import java.awt.Color;
import java.io.IOException;
import java.util.Collection;
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;
import org.jfree.chart.renderer.category.CategoryItemRenderer;
import org.jfree.chart.renderer.category.DefaultCategoryItemRenderer;
import org.jfree.data.category.CategoryDataset;
import org.jfree.ui.RectangleInsets;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
/**
* TODO javadoc.
*
* @author Stephen Connolly
* @since 09-Jan-2008 21:30:15
*/
public class GraphHelper {
public interface CategoryDatasetBuilder {
CategoryDataset buildData();
}
public interface DataCollector {
long getCollectedNumber(AbstractBuildReport<?> action);
String getTitle();
}
/**
* Do not instantiate GraphHelper.
*/
private GraphHelper() {
}
/**
* Getter for property 'graphUnsupported'.
*
* @return Value for property 'graphUnsupported'.
*/
public static boolean isGraphUnsupported() {
return ChartUtil.awtProblem;
}
public static void redirectWhenGraphUnsupported(StaplerResponse rsp, StaplerRequest req) throws IOException {
// not available. send out error message
rsp.sendRedirect2(req.getContextPath() + "/images/headless.png");
}
public static JFreeChart buildChart(final AbstractBuild<?, ?> build, final Integer functionCcnViolationThreshold, final Integer functionNcssViolationThreshold) {
final JFreeChart chart = ChartFactory.createStackedAreaChart(
null, // chart title
null, // unused
"Total Files", // range axis label
buildDataset(build , new DataCollector() {
public String getTitle() {
return "Files";
}
public long getCollectedNumber(AbstractBuildReport action) {
return action.getResults().getFileResults().size();
}
}), // data
PlotOrientation.VERTICAL, // orientation
true, // include legend
true, // tooltips
true // urls
);
chart.setBackgroundPaint(Color.white);
CategoryPlot plot = chart.getCategoryPlot();
plot.setBackgroundPaint(Color.WHITE);
plot.setOutlinePaint(null);
plot.setForegroundAlpha(0.8f);
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);
NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
// crop extra space around the graph
plot.setInsets(new RectangleInsets(0, 0, 0, 5.0));
CategoryItemRenderer firstRender= new DefaultCategoryItemRenderer();
plot.setRenderer(firstRender);
int index = 1;
//Second
build_category(build, chart, index, Color.BLUE, "Non Commenting Source Statements", new CategoryDatasetBuilder() {
public CategoryDataset buildData() {
return buildDataset(build, new DataCollector() {
public String getTitle() {
return "NCSS";
}
public long getCollectedNumber(AbstractBuildReport action) {
return action.getTotals().getFileTotal().getNcss();
}
});
}
});
index ++;
//Third
build_category(build, chart, index, Color.GREEN, "McCabe's Cyclomatic Number", new CategoryDatasetBuilder() {
public CategoryDataset buildData() {
return buildDataset(build, new DataCollector() {
public String getTitle() {
return "CCN";
}
public long getCollectedNumber(AbstractBuildReport action) {
return action.getTotals().getFileTotal().getCcn();
}
});
}
});
index ++;
//Fouth
build_category(build, chart, index, Color.ORANGE, "Total Functions", new CategoryDatasetBuilder() {
public CategoryDataset buildData() {
return buildDataset(build, new DataCollector() {
public String getTitle() {
return "Functions";
}
public long getCollectedNumber(AbstractBuildReport action) {
return action.getTotals().getFileTotal().getFunctions();
}
});
}
});
index ++;
//Fifth
build_category(build, chart, index, Color.CYAN, "CCN Violated Functions", new CategoryDatasetBuilder() {
public CategoryDataset buildData() {
return buildDataset(build, new DataCollector() {
public String getTitle() {
return "CCNVF";
}
public long getCollectedNumber(AbstractBuildReport action) {
Collection<Statistic> functionResults = action.getResults().getFunctionResults();
int ccnViolatedFunctions = 0;
for (Statistic statistic : functionResults) {
if(statistic.getCcn() > functionCcnViolationThreshold.intValue())
ccnViolatedFunctions ++;
}
return ccnViolatedFunctions;
}
});
}
});
index ++;
//Sixth
build_category(build, chart, index, Color.MAGENTA, "NCSS Violated Functions", new CategoryDatasetBuilder() {
public CategoryDataset buildData() {
return buildDataset(build, new DataCollector() {
public String getTitle() {
return "NCSSVF";
}
public long getCollectedNumber(AbstractBuildReport action) {
Collection<Statistic> functionResults = action.getResults().getFunctionResults();
int ncssViolatedFunctions = 0;
for (Statistic statistic : functionResults) {
if(statistic.getNcss() > functionNcssViolationThreshold.intValue())
ncssViolatedFunctions ++;
}
return ncssViolatedFunctions;
}
});
}
});
return chart;
}
private static void build_category(AbstractBuild<?, ?> build,
final JFreeChart chart, int index, Color color, String title, CategoryDatasetBuilder datasetBuilder) {
NumberAxis axis= new NumberAxis(title);
axis.setLabelPaint(color);
axis.setAxisLinePaint(color);
axis.setTickLabelPaint(color);
CategoryPlot categoryPlot = chart.getCategoryPlot();
categoryPlot.setRangeAxis(index, axis);
categoryPlot.setDataset(index, datasetBuilder.buildData());
categoryPlot.mapDatasetToRangeAxis(index,index);
categoryPlot.mapDatasetToDomainAxis(index,0);
CategoryItemRenderer rendu= new DefaultCategoryItemRenderer();
rendu.setPaint(color);
categoryPlot.setRenderer(index,rendu);
}
private static CategoryDataset buildDataset(AbstractBuild<?, ?> build, DataCollector collector) {
DataSetBuilder<String, NumberOnlyBuildLabel> builder = new DataSetBuilder<String, NumberOnlyBuildLabel>();
for (AbstractBuild<?, ?> lastBuild = build; lastBuild != null; lastBuild = lastBuild.getPreviousBuild()) {
ChartUtil.NumberOnlyBuildLabel label = new ChartUtil.NumberOnlyBuildLabel(lastBuild);
AbstractBuildReport action = lastBuild.getAction(AbstractBuildReport.class);
if (action != null) {
builder.add(collector.getCollectedNumber(action), collector.getTitle(), label);
}
}
return builder.build();
}
}