/**
* This program is copyright (c) 2007 Hortis-GRC SA.
*
* This file is part of Sonar.
* Sonar is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Sonar is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Sonar; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
package ch.hortis.sonar.web.charts;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;
import javax.swing.ImageIcon;
import org.apache.commons.io.IOUtils;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.AxisLocation;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.labels.ItemLabelAnchor;
import org.jfree.chart.labels.ItemLabelPosition;
import org.jfree.chart.labels.StandardCategoryItemLabelGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.CombinedRangeCategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.LayeredBarRenderer;
import org.jfree.chart.title.TextTitle;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.ui.TextAnchor;
public class RulesComplianceChart extends BaseChart {
private Map<String, Integer> tendencies;
private CombinedRangeCategoryPlot plotCombined;
private CategoryPlot plotGlobal, plotCategory;
private DefaultCategoryDataset datasetCategory, datasetGlobal;
private LayeredBarRenderer rendererCategory, rendererglobal;
private CategoryAxis categoryAxis;
private NumberAxis numberAxis;
public static final String ERRORLEGEND = "Error level";
public static final String BOTHLEGEND = "Both levels";
private static final int TENDENCY_X_PX = 100;
private static final int TENDENCY_Y_PX_GLOBAL = 10;
private static final int TENDENCY_Y_PX_CATEGORIES = 47;
public RulesComplianceChart( int width, int height ) {
super( width, height );
tendencies = new HashMap<String, Integer>();
configureCategory();
configureGlobal();
configureCombinedPlot();
configureRangeAxis();
}
private void configureCategory(){
datasetCategory = new DefaultCategoryDataset();
categoryAxis = new CategoryAxis();
categoryAxis.setTickLabelFont(getFont());
categoryAxis.setLabelPaint(BASE_COLOR);
categoryAxis.setTickLabelPaint(BASE_COLOR);
categoryAxis.setTickMarkPaint(BASE_COLOR);
rendererCategory = new LayeredBarRenderer();
rendererCategory.setDrawBarOutline( true );
rendererCategory.setSeriesItemLabelsVisible( 0, true );
ItemLabelPosition itemLabelPosition = new ItemLabelPosition(
ItemLabelAnchor.OUTSIDE3,
TextAnchor.HALF_ASCENT_LEFT );
rendererCategory.setBasePositiveItemLabelPosition( itemLabelPosition );
rendererCategory.setMaximumBarWidth( 0.2 );
rendererCategory.setSeriesBarWidth( 0, 1.2 );
rendererCategory.setSeriesBarWidth( 1, 0.3 );
rendererCategory.setSeriesPaint( 0, SERIE1_COLOR );
rendererCategory.setSeriesOutlinePaint( 0, SERIE_BORDER_COLOR );
rendererCategory.setSeriesPaint( 1, SERIE1BIS_COLOR);
rendererCategory.setSeriesOutlinePaint( 1, SERIE_BORDER_COLOR );
rendererCategory.setBaseItemLabelGenerator( new StandardCategoryItemLabelGenerator(
"{2}", new DecimalFormat( "' '0.#'%'" ) ) );
rendererCategory.setBaseItemLabelFont(getFont().deriveFont(FONT_SIZE - 2f));
plotCategory = new CategoryPlot();
plotCategory.setDataset( datasetCategory );
plotCategory.setDomainAxis( categoryAxis );
plotCategory.setRenderer( rendererCategory );
plotCategory.setRangeGridlineStroke( getDashedStroke() );
}
private void configureGlobal(){
datasetGlobal = new DefaultCategoryDataset();
CategoryAxis categoryAxisGlobal = new CategoryAxis();
categoryAxisGlobal.setTickLabelFont(getFont());
categoryAxisGlobal.setLabelPaint(BASE_COLOR);
categoryAxisGlobal.setTickLabelPaint(BASE_COLOR);
categoryAxisGlobal.setTickMarkPaint(BASE_COLOR);
rendererglobal = new LayeredBarRenderer();
try {
rendererglobal = (LayeredBarRenderer) rendererCategory.clone();
} catch (CloneNotSupportedException e) {
}
rendererglobal.setBaseSeriesVisible( false );
rendererglobal.setMaximumBarWidth( 0.75 );
plotGlobal = new CategoryPlot();
plotGlobal.setDataset( datasetGlobal );
plotGlobal.setDomainAxis( categoryAxisGlobal );
plotGlobal.setRenderer( rendererglobal );
plotGlobal.setRangeGridlineStroke( getDashedStroke() );
plotGlobal.setRangeGridlinePaint(BASE_COLOR_LIGHT);
}
private void configureRangeAxis(){
numberAxis = new NumberAxis();
numberAxis.setTickLabelsVisible( false );
numberAxis.setVisible( false );
numberAxis.setUpperBound( 125 );
numberAxis.setLowerBound( -13 );
numberAxis.setLabelPaint(BASE_COLOR);
plotCombined.setRangeAxis( numberAxis );
}
private void configureCombinedPlot(){
plotCombined = new CombinedRangeCategoryPlot();
plotCombined.setOrientation( PlotOrientation.HORIZONTAL );
plotCombined.setRangeAxisLocation( AxisLocation.BOTTOM_OR_LEFT );
plotCombined.add( plotGlobal, 1 );
plotCombined.add( plotCategory, 5 );
}
public void addMeasure( Double value, String category, String legend, Integer tendencyLevel, boolean isGlobal ) {
addMeasure( value, category, legend, isGlobal );
if ( legend.equals( RulesComplianceChart.ERRORLEGEND ) ) {
tendencies.put( getKey( category, legend ), tendencyLevel );
}
}
public void addMeasure( Double value, String category, String legend, boolean isGlobal ) {
if (isGlobal) {
datasetGlobal.addValue( value, legend, category );
} else {
datasetCategory.addValue( value, legend, category );
}
}
public void addMeasure( Double value, String category, String legend, Integer tendencyLevel ) {
addMeasure( value, category, legend, tendencyLevel, false );
}
public void addMeasure( Double value, String category, String legend ) {
addMeasure( value, category, legend, false );
}
private String getKey( Comparable category, Comparable legend ) {
return category + "_" + legend;
}
public void setUndefinedCategory( String category ) {
addMeasure( Double.NaN, category, RulesComplianceChart.ERRORLEGEND, false );
addMeasure( Double.NaN, category, RulesComplianceChart.BOTHLEGEND, false );
}
protected BufferedImage getChartImage() throws IOException {
JFreeChart jfreechart = new JFreeChart( null, TextTitle.DEFAULT_FONT, plotCombined, true );
configureChart(jfreechart, true);
BufferedImage image = getBufferedImage( jfreechart );
int yIndex = TENDENCY_Y_PX_GLOBAL;
for (int i = 0; i < datasetGlobal.getColumnCount(); i++) {
Comparable category = datasetGlobal.getColumnKey( i );
for (int j = 0; j < datasetGlobal.getRowCount(); j++) {
Comparable legend = datasetGlobal.getRowKey( j );
Integer tendency = tendencies.get( getKey( category, legend ) );
if ( tendency != null ) {
drawTendency( image, yIndex, tendency );
}
yIndex += 13;
}
}
yIndex = TENDENCY_Y_PX_CATEGORIES;
for (int i = 0; i < datasetCategory.getColumnCount(); i++) {
Comparable category = datasetCategory.getColumnKey( i );
for (int j = 0; j < datasetCategory.getRowCount(); j++) {
Comparable legend = datasetCategory.getRowKey( j );
Integer tendency = tendencies.get( getKey( category, legend ) );
if ( tendency != null ) {
drawTendency( image, yIndex, tendency );
}
yIndex += 13;
}
}
return image;
}
private void drawTendency( BufferedImage chartImage, int yIndex, Integer tendency )
throws IOException {
InputStream in = this.getClass().getResourceAsStream( "/ch/hortis/sonar/web/charts/tendency/" + tendency + ".gif" );
ImageIcon icon = new ImageIcon( IOUtils.toByteArray( in ) );
chartImage.getGraphics().drawImage( icon.getImage(), TENDENCY_X_PX, yIndex, null );
}
}