/*
* 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";
}
}