WWZPlotPane.java
/**
* VStar: a statistical analysis tool for variable star data.
* Copyright (C) 2010 AAVSO (http://www.aavso.org/)
*
* This program 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.
*
* 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.aavso.tools.vstar.ui.dialog.period.wwz;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JPanel;
import org.aavso.tools.vstar.ui.mediator.Mediator;
import org.aavso.tools.vstar.ui.mediator.message.PeriodAnalysisSelectionMessage;
import org.aavso.tools.vstar.ui.model.plot.WWZ2DPlotModel;
import org.aavso.tools.vstar.util.IStartAndCleanup;
import org.aavso.tools.vstar.util.Tolerance;
import org.aavso.tools.vstar.util.notification.Listener;
import org.aavso.tools.vstar.util.period.IPeriodAnalysisDatum;
import org.aavso.tools.vstar.util.period.wwz.WWZStatistic;
import org.jfree.chart.ChartMouseEvent;
import org.jfree.chart.ChartMouseListener;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.entity.XYItemEntity;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.data.Range;
import org.jfree.data.general.DatasetChangeEvent;
import org.jfree.data.general.DatasetChangeListener;
/**
* This is a pane that contains a WWZ plot chart.
*/
public class WWZPlotPane extends JPanel implements ChartMouseListener,
DatasetChangeListener, IStartAndCleanup {
private static int DEFAULT_CHART_PANEL_WIDTH = 680;
private static int DEFAULT_CHART_PANEL_HEIGHT = 420;
private JFreeChart chart;
private WWZ2DPlotModel model;
private double minRange;
private double maxRange;
private Listener<PeriodAnalysisSelectionMessage> periodAnalysisSelectionListener;
/**
* Constructor
*
*/
public WWZPlotPane(JFreeChart chart, WWZ2DPlotModel model, double minRange,
double maxRange) {
super();
this.chart = chart;
this.model = model;
this.minRange = minRange;
this.maxRange = maxRange;
this.setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
this.setBorder(BorderFactory.createEtchedBorder());
ChartPanel chartPanel = new ChartPanel(chart);
this.add(chartPanel);
configureChart();
chartPanel.addChartMouseListener(this);
model.addChangeListener(this);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(DEFAULT_CHART_PANEL_WIDTH, DEFAULT_CHART_PANEL_HEIGHT);
}
/**
* @return the chart
*/
public JFreeChart getChart() {
return chart;
}
/**
* @return the model
*/
public WWZ2DPlotModel getModel() {
return model;
}
/**
* Set the renderer for the plot.
*
* @param renderer
* The XYItemRenderer subclass instance to set.
*/
public void setRenderer(XYItemRenderer renderer) {
chart.getXYPlot().setRenderer(renderer);
}
protected void configureChart() {
chart.getXYPlot().setBackgroundPaint(Color.WHITE);
chart.getXYPlot().setDomainCrosshairValue(0);
chart.getXYPlot().setRangeCrosshairValue(0);
chart.getXYPlot().setDomainCrosshairVisible(true);
chart.getXYPlot().setRangeCrosshairVisible(true);
double rangeDelta = maxRange - minRange;
if (Double.isFinite(rangeDelta) &&
!Tolerance.areClose(rangeDelta, 0.0, 1e-12, true)) {
chart.getXYPlot().getRangeAxis().setRange(
new Range(minRange, maxRange));
} else {
chart.getXYPlot().getRangeAxis().setRange(
new Range(-Double.MAX_VALUE / 2, Double.MAX_VALUE / 2));
}
}
@Override
public void chartMouseClicked(ChartMouseEvent event) {
if (event.getEntity() instanceof XYItemEntity) {
XYItemEntity entity = (XYItemEntity) event.getEntity();
int item = entity.getItem();
PeriodAnalysisSelectionMessage message = new PeriodAnalysisSelectionMessage(
this, model.getStats().get(item), item);
message.setTag(Mediator.getParentDialogName(this));
Mediator.getInstance().getPeriodAnalysisSelectionNotifier()
.notifyListeners(message);
}
}
@Override
public void chartMouseMoved(ChartMouseEvent event) {
// Nothing to do: see period analysis 2D plot pane
}
@Override
public void datasetChanged(DatasetChangeEvent event) {
// Nothing to do: see period analysis 2D plot pane
}
/**
* Update the crosshairs according to the selected data point.
*/
protected Listener<PeriodAnalysisSelectionMessage> createPeriodAnalysisListener() {
final Component parent = this;
return new Listener<PeriodAnalysisSelectionMessage>() {
@Override
public void update(PeriodAnalysisSelectionMessage info) {
if (!Mediator.isMsgForDialog(Mediator.getParentDialog(WWZPlotPane.this), info))
return;
if (info.getSource() != parent) {
// Find the datapoint in the model (could be minimal or full
// stats).
IPeriodAnalysisDatum datum = info.getDataPoint();
WWZStatistic foundStat = null;
for (WWZStatistic stat : model.getStats()) {
if (stat.equals(datum)) {
foundStat = stat;
break;
}
}
if (foundStat != null) {
double x = foundStat.getValue(model.getDomainType());
double y = foundStat.getValue(model.getRangeType());
chart.getXYPlot().setDomainCrosshairValue(x);
chart.getXYPlot().setRangeCrosshairValue(y);
}
}
}
@Override
public boolean canBeRemoved() {
return true;
}
};
}
@Override
public void startup() {
periodAnalysisSelectionListener = createPeriodAnalysisListener();
Mediator.getInstance().getPeriodAnalysisSelectionNotifier()
.addListener(periodAnalysisSelectionListener);
}
@Override
public void cleanup() {
Mediator.getInstance().getPeriodAnalysisSelectionNotifier()
.removeListenerIfWilling(periodAnalysisSelectionListener);
}
}