org.jax.maanova.plot.RenderChartImageTask.java Source code

Java tutorial

Introduction

Here is the source code for org.jax.maanova.plot.RenderChartImageTask.java

Source

/*
 * Copyright (c) 2010 The Jackson Laboratory
 * 
 * This 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 3 of the License, or
 * (at your option) any later version.
 *
 * This software 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 this software.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.jax.maanova.plot;

import java.awt.image.BufferedImage;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.jax.util.concurrent.SimpleLongRunningTask;
import org.jfree.chart.ChartRenderingInfo;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.event.ChartChangeEvent;
import org.jfree.chart.event.ChartChangeListener;

/**
 * A long running task that is useful for rendering chart images outside
 * of the AWT Event thread.
 * @author <A HREF="mailto:keith.sheppard@jax.org">Keith Sheppard</A>
 */
public class RenderChartImageTask extends SimpleLongRunningTask implements Runnable {
    /**
     * our logger
     */
    private static final Logger LOG = Logger.getLogger(RenderChartImageTask.class.getName());

    private volatile JFreeChart chart;

    private volatile int width;

    private volatile int height;

    private final ChartRenderingInfo chartRenderingInfo;

    private final ArrayBlockingQueue<BufferedImage> bufferedImageQueue;

    private final ArrayBlockingQueue<Object> renderRequestQueue;

    private final ChartChangeListener chartChageListener = new ChartChangeListener() {
        /**
         * {@inheritDoc}
         */
        public void chartChanged(ChartChangeEvent event) {
            RenderChartImageTask.this.renderRequestQueue.offer(new Object());
        }
    };

    /**
     * Constructor
     * @param chartRenderingInfo
     *          the chart rendering info
     */
    public RenderChartImageTask(ChartRenderingInfo chartRenderingInfo) {
        this.chartRenderingInfo = chartRenderingInfo;
        this.bufferedImageQueue = new ArrayBlockingQueue<BufferedImage>(1);
        this.renderRequestQueue = new ArrayBlockingQueue<Object>(1);
    }

    /**
     * Setter for the chart
     * @param chart the chart
     */
    public void setChart(JFreeChart chart) {
        if (this.chart != null) {
            this.chart.removeChangeListener(this.chartChageListener);
        }

        this.chart = chart;

        if (chart != null) {
            chart.addChangeListener(this.chartChageListener);
        }

        this.renderRequestQueue.offer(new Object());
    }

    /**
     * Getter for the chart
     * @return the chart
     */
    public JFreeChart getChart() {
        return this.chart;
    }

    /**
     * Update the image size
     * @param width
     *          the new width
     * @param height
     *          the new height
     */
    public void setSize(int width, int height) {
        this.width = width;
        this.height = height;

        this.renderRequestQueue.offer(new Object());
    }

    /**
     * {@inheritDoc}
     */
    public void run() {
        try {
            while (true) {
                // wait until the chart needs to be updated
                this.renderRequestQueue.take();

                if (this.getWorkUnitsCompleted() == 1) {
                    // each render cycle is a new work unit
                    this.setTotalWorkUnits(1);
                    this.setWorkUnitsCompleted(0);
                }

                // get a snapshot of the updated chart width and height
                JFreeChart tmpChart = this.chart;
                int tmpWidth = this.width;
                int tmpHeight = this.height;

                // if any values are bad leave the buffered image as null
                BufferedImage bi = null;
                if (tmpChart != null && tmpWidth > 0 && tmpHeight > 0) {
                    bi = tmpChart.createBufferedImage(tmpWidth, tmpHeight, this.chartRenderingInfo);
                }

                if (bi != null) {
                    // clear any old image before putting our shiny new image
                    this.bufferedImageQueue.poll();
                    this.bufferedImageQueue.put(bi);
                }

                // don't bother setting work to complete if we know there
                // is a pending request in the queue
                if (this.renderRequestQueue.isEmpty()) {
                    this.setWorkUnitsCompleted(1);
                }
            }
        } catch (InterruptedException ex) {
            LOG.log(Level.SEVERE, "Error rendering chart image", ex);
        }
    }

    /**
     * Getter for the next image. This function blocks until there is an
     * updated image to get
     * @return
     *          the next buffered image
     */
    public BufferedImage getNextImage() {
        try {
            return this.bufferedImageQueue.take();
        } catch (InterruptedException ex) {
            LOG.log(Level.SEVERE, "Error getting image from buffered image queue", ex);
            return null;
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String getTaskName() {
        return "Rendering Graph Image";
    }
}