org.webcat.grader.graphs.JFreeChartComponent.java Source code

Java tutorial

Introduction

Here is the source code for org.webcat.grader.graphs.JFreeChartComponent.java

Source

/*==========================================================================*\
 |  $Id: JFreeChartComponent.java,v 1.3 2010/10/19 18:37:37 aallowat Exp $
 |*-------------------------------------------------------------------------*|
 |  Copyright (C) 2010 Virginia Tech
 |
 |  This file is part of Web-CAT.
 |
 |  Web-CAT is free software; you can redistribute it and/or modify
 |  it under the terms of the GNU Affero General Public License as published
 |  by the Free Software Foundation; either version 3 of the License, or
 |  (at your option) any later version.
 |
 |  Web-CAT 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 Affero General Public License
 |  along with Web-CAT; if not, see <http://www.gnu.org/licenses/>.
\*==========================================================================*/

package org.webcat.grader.graphs;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import org.apache.log4j.Logger;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.XYDataset;
import org.webcat.core.Application;
import org.webcat.core.WCComponent;
import com.webobjects.appserver.WOContext;
import com.webobjects.appserver.WOElement;
import com.webobjects.foundation.NSData;

//-------------------------------------------------------------------------
/**
 * An abstract base class for the other components that render JFreeChart
 * images (StackedAreaChart and HistogramChart).
 *
 * @author Tony Allevato
 * @version $Id: JFreeChartComponent.java,v 1.3 2010/10/19 18:37:37 aallowat Exp $
 */
public abstract class JFreeChartComponent extends WCComponent {
    //~ Constructors ..........................................................

    // ----------------------------------------------------------
    /**
     * Initializes a new instance of the JFreeChartComponent class.
     *
     * @param context the context
     */
    public JFreeChartComponent(WOContext context) {
        super(context);
    }

    //~ Methods ...............................................................

    // ----------------------------------------------------------
    /**
     * Automatically provides the component template for subclasses.
     *
     * @return the component template
     */
    @Override
    public WOElement template() {
        if (cachedTemplate == null) {
            String htmlTemplate = "<webobject name=\"ShouldDisplay\">" + "<webobject name=\"Chart\"/>"
                    + "</webobject>";

            String bindingDefinitions = "Chart: WOImage {" + "data     = pngChart;" + "mimeType = \"image/png\";";

            if (!sizesToFit()) {
                bindingDefinitions += "width    = chartWidth;" + "height   = chartHeight;";
            }

            if (style != null) {
                bindingDefinitions += "style    = \"" + style + "\";";
            }

            bindingDefinitions += "title    = title;" + "alt      = title;" + "}" + "ShouldDisplay: WOConditional {"
                    + "condition = shouldDisplay;" + "}";

            cachedTemplate = templateWithHTMLString(null, null, htmlTemplate, bindingDefinitions, null,
                    Application.application().associationFactoryRegistry(),
                    Application.application().namespaceProvider());
        }

        return cachedTemplate;
    }

    // ----------------------------------------------------------
    /**
     * Gets the dataset used to generate this chart.
     *
     * @return the dataset
     */
    public XYDataset dataset() {
        return dataset;
    }

    // ----------------------------------------------------------
    /**
     * Sets the dataset used to generate this chart.
     *
     * @param aDataset the dataset
     */
    public void setDataset(XYDataset aDataset) {
        dataset = aDataset;

        // Clear the cached chart so that it has to be regenerated with the
        // new data.
        pngChart = null;
    }

    // ----------------------------------------------------------
    /**
     * Gets the title to display at the top of this chart.
     *
     * @return the chart title
     */
    public String title() {
        return title;
    }

    // ----------------------------------------------------------
    /**
     * Sets the title to display at the top of this chart.
     *
     * @param aTitle the chart title
     */
    public void setTitle(String aTitle) {
        title = aTitle;

        // Clear the cached chart so that it has to be regenerated with the
        // new labels.
        pngChart = null;
    }

    // ----------------------------------------------------------
    /**
     * Gets the label to display on the x-axis of this chart.
     *
     * @return the x-axis label
     */
    public String xAxisLabel() {
        return xAxisLabel;
    }

    // ----------------------------------------------------------
    /**
     * Sets the label to display on the x-axis of this chart.
     *
     * @param aLabel the x-axis label
     */
    public void setXAxisLabel(String aLabel) {
        xAxisLabel = aLabel;

        // Clear the cached chart so that it has to be regenerated with the
        // new labels.
        pngChart = null;
    }

    // ----------------------------------------------------------
    /**
     * Gets the label to display on the y-axis of this chart.
     *
     * @return the y-axis label
     */
    public String yAxisLabel() {
        return yAxisLabel;
    }

    // ----------------------------------------------------------
    /**
     * Sets the label to display on the y-axis of this chart.
     *
     * @param aLabel the y-axis label
     */
    public void setYAxisLabel(String aLabel) {
        yAxisLabel = aLabel;

        // Clear the cached chart so that it has to be regenerated with the
        // new labels.
        pngChart = null;
    }

    // ----------------------------------------------------------
    /**
     * Gets the orientation of this chart.
     *
     * @return the chart orientation
     */
    public PlotOrientation orientation() {
        return orientation;
    }

    // ----------------------------------------------------------
    /**
     * Sets the orientation of this chart.
     *
     * @param anOrientation the chart orientation
     */
    public void setOrientation(PlotOrientation anOrientation) {
        orientation = anOrientation;

        // Clear the cached chart so that it has to be regenerated with the
        // new orientation.
        pngChart = null;
    }

    // ----------------------------------------------------------
    /**
     * Gets the width of the chart.
     *
     * @return the width of the chart
     */
    public int chartWidth() {
        // Force generation of the cached chart, which may force the size of
        // the image to change.
        pngChart();

        return chartWidth;
    }

    // ----------------------------------------------------------
    /**
     * Sets the width of the chart.
     *
     * @param value the width of the chart
     */
    public void setChartWidth(int value) {
        chartWidth = value;

        // Clear the cached chart so that it has to be regenerated with the
        // new size.
        pngChart = null;
    }

    // ----------------------------------------------------------
    /**
     * Gets the height of the chart.
     *
     * @return the height of the chart
     */
    public int chartHeight() {
        // Force generation of the cached chart, which may force the size of
        // the image to change.
        pngChart();

        return chartHeight;
    }

    // ----------------------------------------------------------
    /**
     * Sets the height of the chart.
     *
     * @param value the height of the chart
     */
    public void setChartHeight(int value) {
        chartHeight = value;

        // Clear the cached chart so that it has to be regenerated with the
        // new size.
        pngChart = null;
    }

    // ----------------------------------------------------------
    /**
     * Gets the label to display on the x-axis of this chart.
     *
     * @return the x-axis label
     */
    public String style() {
        return style;
    }

    // ----------------------------------------------------------
    /**
     * Sets the label to display on the x-axis of this chart.
     *
     * @param aLabel the x-axis label
     */
    public void setStyle(String aStyle) {
        style = aStyle;
    }

    // ----------------------------------------------------------
    /**
     * Gets a value indicating whether the specified chart width and height
     * values should be ignored and the image tag should automatically size to
     * fit the chart.
     *
     * @return true to ignore the chart width/height; false to force the
     *     specified dimensions
     */
    public boolean sizesToFit() {
        return false;
    }

    // ----------------------------------------------------------
    /**
     * Gets a value indicating whether this chart should be displayed.
     *
     * @return true to display the chart; false to hide it
     */
    public boolean shouldDisplay() {
        return dataset != null;
    }

    // ----------------------------------------------------------
    /**
     * Gets the PNG image data for this chart.
     *
     * @return an NSData object containing the PNG image data
     */
    public NSData pngChart() {
        if (pngChart != null) {
            return pngChart;
        }

        // We synchronize on the ChartFactory class since the chart theme that
        // we use is based on the user's settings, and we want to ensure that
        // only one user is modifying it at a time.
        synchronized (ChartFactory.class) {
            WCChartTheme chartTheme = new WCChartTheme(wcSession().theme());
            ChartFactory.setChartTheme(chartTheme);

            JFreeChart chart = generateChart(chartTheme);

            ByteArrayOutputStream baos = new ByteArrayOutputStream();

            // Adjust the chart height, if necessary.

            double maxItems = 2;

            for (int i = 0; i < dataset.getItemCount(0); i++) {
                double x = dataset.getYValue(0, i);

                if (x > maxItems) {
                    maxItems = x;
                }
            }

            int minHeight = minimumHeight();

            if (maxItems < 10 && chartHeight > minHeight) {
                chartHeight -= minHeight;
                maxItems -= 2;
                chartHeight = (int) (chartHeight * maxItems / 10 + 0.5);
                chartHeight += minHeight;
            }

            try {
                ChartUtilities.writeChartAsPNG(baos, chart, chartWidth, chartHeight);

                pngChart = new NSData(baos.toByteArray());
            } catch (IOException e) {
                log.error("Exception creating chart", e);
            }
        }

        return pngChart;
    }

    // ----------------------------------------------------------
    /**
     * Gets the minimum height that this chart can be sized.
     *
     * @return the minimum height of the chart
     */
    protected int minimumHeight() {
        return 100;
    }

    // ----------------------------------------------------------
    /**
     * Generates the JFreeChart object for the chart. Subclasses must override
     * this to provide the appropriate type of chart.
     *
     * @param chartTheme the chart theme used to determine colors
     * @return the JFreeChart object for the chart
     */
    protected abstract JFreeChart generateChart(WCChartTheme chartTheme);

    //~ Static/instance variables .............................................

    private WOElement cachedTemplate;
    private NSData pngChart;

    private XYDataset dataset;
    private int chartWidth = 400;
    private int chartHeight = 400;
    private String title;
    private String xAxisLabel;
    private String yAxisLabel;
    private String style;
    private PlotOrientation orientation = PlotOrientation.VERTICAL;

    protected static Logger log = Logger.getLogger(JFreeChartComponent.class);
}