/*
* JABM - Java Agent-Based Modeling Toolkit
* Copyright (C) 2013 Steve Phelps
*
* This program 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 program 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.
*/
package net.sourceforge.jabm.view;
import java.awt.Dimension;
import java.awt.HeadlessException;
import java.io.Serializable;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
import javax.swing.JComponent;
import javax.swing.SwingUtilities;
import net.sourceforge.jabm.event.ReportVariablesChangedEvent;
import net.sourceforge.jabm.event.SimEvent;
import net.sourceforge.jabm.report.ReportWithGUI;
import net.sourceforge.jabm.report.Timeseries;
import org.apache.log4j.Logger;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.data.DomainOrder;
import org.jfree.data.general.Dataset;
import org.jfree.data.general.DatasetChangeEvent;
import org.jfree.data.general.DatasetChangeListener;
import org.jfree.data.general.DatasetGroup;
import org.jfree.data.xy.XYDataset;
import org.springframework.beans.factory.InitializingBean;
/**
* A graphical report that renders an underlying time series ({@link Timeseries}
* ) as a JFreeChart time series chart. This report listens for events from
* the underlying Timeseries object and notifies its chart whenever the series
* is updated.
*
* @author Steve Phelps
*/
public class TimeSeriesChart implements XYDataset, ReportWithGUI, Serializable,
InitializingBean {
/**
* The underlying time series which is the model for our chart.
*/
protected Timeseries series;
protected Map<Object, Number> variableBindings = new LinkedHashMap<Object, Number>();
protected LinkedList<Object> variableNames = new LinkedList<Object>();
protected LinkedList<DatasetChangeListener> listeners = new LinkedList<DatasetChangeListener>();
protected String chartTitle;
protected String rangeAxisLabel = "";
/**
* The JFreeChart ChartPanel which contains the actual swing component
* for the chart.
*/
protected ChartPanel chartPanel;
static Logger logger = Logger.getLogger(TimeSeriesChart.class);
public TimeSeriesChart() throws HeadlessException {
super();
}
@Override
public void afterPropertiesSet() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
initialiseGUI();
}
});
}
public void initialiseGUI() {
String name = chartTitle;
if (name == null) {
name = series.getName();
}
computeVariableNames();
// series.initialise(null);
JFreeChart chart = ChartFactory.createTimeSeriesChart(name, // chart
// title
"t", // domain axis label
rangeAxisLabel, // range axis label
this, // data
true, // include legend
true, // tooltips?
false // URLs?
);
chartPanel = new ChartPanel(chart, true);
chartPanel.setPreferredSize(new Dimension(500, 270));
computeVariableNames();
series.addListener(this);
}
public Map<Object, Number> getVariableBindings() {
return series.getVariableBindings();
}
public void computeVariableNames() {
this.variableNames = new LinkedList<Object>(series.getyVariableNames());
}
/**
* When this report is computed it notifies its listeners (typically
* the JFreeChart swing component) that its data set has changed.
*/
public void compute(ReportVariablesChangedEvent event) {
final Dataset eventOriginator = this;
for (DatasetChangeListener listener : listeners) {
listener.datasetChanged(new DatasetChangeEvent(eventOriginator,
eventOriginator));
}
}
public void dispose(SimEvent event) {
series.dispose(event);
}
public void initialise(SimEvent event) {
series.initialise(event);
}
public int getSeriesCount() {
int n = series.getNumberOfSeries();
return n;
}
@SuppressWarnings("rawtypes")
public Comparable getSeriesKey(int seriesIndex) {
// if (variableNames.size() == 0) {
// //TODO
// return "";
// }
String result = this.variableNames.get(seriesIndex).toString();
return result;
}
@SuppressWarnings("rawtypes")
public int indexOf(Comparable seriesKey) {
int result = variableNames.indexOf(seriesKey);
return result;
}
public DatasetGroup getGroup() {
// TODO Auto-generated method stub
return null;
}
public void addChangeListener(DatasetChangeListener arg0) {
listeners.add(arg0);
}
public void removeChangeListener(DatasetChangeListener arg0) {
listeners.remove(arg0);
}
public void setGroup(DatasetGroup arg0) {
}
public DomainOrder getDomainOrder() {
return null;
}
public int getItemCount(int seriesIndex) {
int result = series.size(seriesIndex);
return result;
}
public Number getX(int seriesIndex, int itemIndex) {
return series.getX(seriesIndex, itemIndex);
}
public double getXValue(int seriesIndex, int itemIndex) {
double result = getX(seriesIndex, itemIndex).doubleValue();
return result;
}
public Number getY(int seriesIndex, int itemIndex) {
return series.getY(seriesIndex, itemIndex);
}
public double getYValue(int seriesIndex, int itemIndex) {
return getY(seriesIndex, itemIndex).doubleValue();
}
public void eventOccurred(SimEvent event) {
// series.eventOccurred(event);
if (event instanceof ReportVariablesChangedEvent) {
compute((ReportVariablesChangedEvent) event);
}
}
public Timeseries getSeries() {
return series;
}
public void setSeries(Timeseries series) {
this.series = series;
}
public String getChartTitle() {
return chartTitle;
}
public void setChartTitle(String chartTitle) {
this.chartTitle = chartTitle;
}
public String getRangeAxisLabel() {
return rangeAxisLabel;
}
public void setRangeAxisLabel(String rangeAxisLabel) {
this.rangeAxisLabel = rangeAxisLabel;
}
@Override
public String getName() {
return chartTitle;
}
@Override
public JComponent getComponent() {
return chartPanel;
}
}