blob: f802d0dd0006b6266a8bc1673d07c4af74ff0652 [file] [log] [blame]
package com.pivotal.jvsd;
import com.pivotal.jvsd.stats.StatFileParser.StatValue;
import com.pivotal.jvsd.stats.Utility;
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Paint;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.geom.Rectangle2D;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import com.pivotal.jvsd.util.PanelOverlay;
import org.jfree.chart.ChartColor;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartMouseEvent;
import org.jfree.chart.ChartMouseListener;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.AxisLocation;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.entity.LegendItemEntity;
import org.jfree.chart.labels.XYToolTipGenerator;
import org.jfree.chart.panel.CrosshairOverlay;
import org.jfree.chart.plot.Crosshair;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.StandardXYItemRenderer;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.RectangleEdge;
/**
*
* @author Vince Ford
*/
public class VSDChartWindow extends JFrame
implements ActionListener, WindowListener, ChartMouseListener, KeyListener {
static int chartID = -1;
private JMenuBar menubar = null;
private VSDMainWindow mainWindow;
// private ChartSidePanel valuePanel = null;
private ArrayList<StatValue> statsArray = null;
private JFreeChart chart = null;
private ChartPanel cp = null;
private AtomicInteger plotNumber;
private CrosshairOverlay crosshairOverlay;
private HUD hud;
private static final float dash1[] = {5.0f};
private static final BasicStroke dashed =
new BasicStroke(0.5f,
BasicStroke.CAP_BUTT,
BasicStroke.JOIN_MITER,
5.0f, dash1, 0.0f);
private static final SimpleDateFormat X_AXIS_DATE_FORMAT =
new SimpleDateFormat("HH:mm:ss.SSS");
private static Color PLOT_BACKGROUND = new Color(220, 220, 220);
private static Color SELECTED_SERIES = new Color(128, 0, 0);
private XYSeriesCollection lastDataset = null;
private Comparable lastSeries;
private Paint lastPaint;
static synchronized int updateChartID() {
chartID++;
return chartID;
}
public VSDChartWindow(StatValue stat, VSDMainWindow parentContainer) {
this.mainWindow = parentContainer;
String name = stat.getDescriptor().getName();
this.setTitle("Chart" + updateChartID() + "_" + name);
statsArray = new ArrayList<StatValue>();
plotNumber = new AtomicInteger(0);
plotNumber.getAndIncrement();
initializeChartWindow();
createChart(stat);
this.addKeyListener(this);
}
private void initializeChartWindow() {
this.setSize((int) (Utility.getHorizontalScreenSize() * 0.75),
(int) (Utility.getVerticalScreenSize() * 0.75));
this.addWindowListener(this);
createMenus();
this.getContentPane().setLayout(new BorderLayout());
// this.valuePanel = new ChartSidePanel(this);
// JScrollPane scrollpane = new JScrollPane(valuePanel);
// scrollpane.
// setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
// this.getContentPane().add(scrollpane, BorderLayout.EAST);
}
private void createMenus() {
menubar = new JMenuBar();
JMenu menu = Utility.createMenu("Chart", menubar);
Utility.createMenuItem("Close", menu, this);
menu = Utility.createMenu("Edit", menubar);
menu.setEnabled(false);
menu = Utility.createMenu("Line", menubar);
menu.setEnabled(false);
menu = Utility.createMenu("Help", menubar);
menu.setEnabled(false);
this.setJMenuBar(menubar);
}
public void actionPerformed(ActionEvent e) {
Object o = e.getSource();
if (o instanceof JMenuItem) {
JMenuItem mi = (JMenuItem) o;
String menuItem = mi.getActionCommand();
if (menuItem.equals("Close")) {
this.setVisible(false);
mainWindow.removeChartWindow(this);
}
} else {
if (o instanceof JComboBox) {
JComboBox cb = (JComboBox) o;
if (cb.getName().equals("StatComboBox")) {
String statname = (String) cb.getSelectedItem();
StatValue sv = this.lookupIndexedStatName(statname);
// valuePanel.setMax(sv.getSnapshotsMaximum());
// valuePanel.setMin(sv.getSnapshotsMinimum());
// valuePanel.setStdDev(sv.getSnapshotsStandardDeviation());
// valuePanel.setMean(sv.getSnapshotsAverage());
// valuePanel.setDescription(sv.getDescriptor().getDescription());
// valuePanel.setUnits(sv.getDescriptor().getUnits());
// valuePanel.setSamples(sv.getSnapshotsSize());
// valuePanel.setFilterComboBox(sv.getFilter());
// valuePanel.updateValues();
}
}
}
}
private XYSeries createXYSeries(StatValue sv) {
long[] timestamps = sv.getRawAbsoluteTimeStamps();
double[] dataValue;
long timeSampleAverage = Utility.computeTimeSampleAverage(timestamps);
long samplePeriod = timeSampleAverage / 1000;
XYSeries sample = new XYSeries(getIndexedStatName(sv));
timestamps = sv.getRawAbsoluteTimeStamps();
dataValue = sv.getRawSnapshots();
if (sv.getFilter() == sv.FILTER_PERSEC) {
for (int d = 0; d < timestamps.length; d++) {
long timestamp = timestamps[d];
double value = dataValue[d];
if (d == 0) {
value = Utility.
computePerSecondValue(timestamp,
timestamp - timeSampleAverage, value,
sv.getSnapshotsAverage(), samplePeriod);
sample.add(timestamp, value);
} else {
value = Utility.
computePerSecondValue(timestamp, timestamps[d - 1], value,
dataValue[d - 1], samplePeriod);
sample.add(timestamp, value);
}
}
} else {
for (int d = 0; d < timestamps.length; d++) {
sample.add(timestamps[d], dataValue[d]);
}
}
return sample;
}
private void createChart(StatValue sv) {
statsArray.add(sv);
updateValuePanel(sv);
if (!(sv.getSnapshotsAverage() == 0 &&
sv.getSnapshotsMaximum() == 0 &&
sv.getSnapshotsMinimum() == 0)) {
XYSeries series = createXYSeries(sv);
XYSeriesCollection xysc = new XYSeriesCollection(series);
chart = ChartFactory.createTimeSeriesChart(null, null,
sv.getDescriptor().getUnits(), xysc, true, true, true);
XYPlot plot = chart.getXYPlot();
plot.setRangePannable(true);
plot.setDomainPannable(true);
plot.setBackgroundPaint(PLOT_BACKGROUND);
// plot.setDrawingSupplier(new VSDDrawingSupplier());
cp = new ChartPanel(chart);
this.getContentPane().add(cp, BorderLayout.CENTER);
cp.setMouseWheelEnabled(true);
cp.setMouseZoomable(true);
cp.addChartMouseListener(this);
hud = new HUD();
cp.addOverlay(new PanelOverlay(hud, cp));
}
}
private void updateValuePanel(StatValue sv) {
// valuePanel.setMax(sv.getSnapshotsMaximum());
// valuePanel.setMin(sv.getSnapshotsMinimum());
// valuePanel.setStdDev(sv.getSnapshotsStandardDeviation());
// valuePanel.setMean(sv.getSnapshotsAverage());
// valuePanel.setDescription(sv.getDescriptor().getDescription());
// valuePanel.setStatName(getIndexedStatName(sv));
// valuePanel.setUnits(sv.getDescriptor().getUnits());
// valuePanel.setSamples(sv.getSnapshotsSize());
// valuePanel.updateValues();
}
private String getIndexedStatName(StatValue sv) {
int index = statsArray.indexOf(sv);
String statname = Integer.toString(index) + "_" + sv.getDescriptor().
getName();
return statname;
}
private StatValue lookupIndexedStatName(String name) {
int charIndex = name.indexOf("_");
int svIndex = Integer.parseInt(name.substring(0, charIndex));
return statsArray.get(svIndex);
}
public void windowOpened(WindowEvent e) {
}
public void windowClosing(WindowEvent e) {
mainWindow.removeChartWindow(this);
}
public void windowClosed(WindowEvent e) {
}
public void windowIconified(WindowEvent e) {
}
public void windowDeiconified(WindowEvent e) {
}
public void windowActivated(WindowEvent e) {
}
public void windowDeactivated(WindowEvent e) {
}
public void addToChart(List<StatValue> stats) {
for (StatValue sv : stats) {
statsArray.add(sv);
if (!(sv.getSnapshotsAverage() == 0 &&
sv.getSnapshotsMaximum() == 0 &&
sv.getSnapshotsMinimum() == 0)) {
XYSeries series = createXYSeries(sv);
XYItemRenderer renderer2 = new StandardXYItemRenderer();
XYPlot plot = chart.getXYPlot();
NumberAxis currentAxis = null;
boolean foundAxis = false;
int axisnum = 0;
for (axisnum = 0; axisnum < plot.getRangeAxisCount(); axisnum++) {
currentAxis = (NumberAxis) plot.getRangeAxis(axisnum);
if (currentAxis.getLabel().equals(sv.getDescriptor().getUnits())) {
foundAxis = true;
break;
}
}
if (!foundAxis) {
NumberAxis numAxis = new NumberAxis(sv.getDescriptor().getUnits());
numAxis.setAutoRange(true);
numAxis.setRange(0, sv.getSnapshotsMaximum() * 1.1);
plot.setRangeAxis(plotNumber.get(), numAxis);
plot.setDataset(plotNumber.get(), new XYSeriesCollection(series));
plot.setRangeAxisLocation(plotNumber.get(),
AxisLocation.BOTTOM_OR_LEFT);
plot.mapDatasetToRangeAxis(plotNumber.get(), plotNumber.get());
plot.setRenderer(plotNumber.get(), renderer2);
plotNumber.incrementAndGet();
} else {
currentAxis.setAutoRange(true);
if ((sv.getSnapshotsMaximum() * 1.1) > currentAxis.getRange().
getUpperBound()) {
currentAxis.setRange(0, sv.getSnapshotsMaximum() * 1.1);
}
XYSeriesCollection a = (XYSeriesCollection) plot.getDataset(axisnum);
a.addSeries(series);
plot.setRangeAxis(axisnum, currentAxis);
// plot.setDataset(priorPlotnumber, xysc);
plot.mapDatasetToRangeAxis(axisnum, axisnum);
// plot.setRenderer(priorPlotnumber, renderer2);
}
renderer2.setBaseToolTipGenerator(new XYToolTipGenerator() {
public String generateToolTip(XYDataset dataset, int series,
int item) {
Number x = dataset.getX(series, item);
Number y = dataset.getY(series, item);
String yf = String.format("%.2f", y);
Date date = new Date(x.longValue());
DateFormat df = DateFormat.
getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
String tooltip = df.format(date) + "," + yf;
return tooltip;
}
});
cp.setDisplayToolTips(true);
updateValuePanel(sv);
}
}
}
@Override
public void chartMouseClicked(ChartMouseEvent cme) {
if (cme.getEntity() instanceof LegendItemEntity) {
LegendItemEntity lie = (LegendItemEntity) cme.getEntity();
XYPlot plot = cme.getChart().getXYPlot();
// Reset the previously selected...
if (lastDataset != null) {
int idx = lastDataset.getSeriesIndex(lastSeries);
plot.getRendererForDataset(lastDataset).setSeriesPaint(idx, lastPaint);
}
// Did we just re-select our last one?
if (lastDataset == lie.getDataset()) {
lastDataset = null;
return;
}
lastSeries = lie.getSeriesKey();
lastDataset = (XYSeriesCollection) lie.getDataset();
int idx = lastDataset.getSeriesIndex(lastSeries);
XYItemRenderer r = plot.getRendererForDataset(lastDataset);
lastPaint = r.getSeriesPaint(idx);
r.setSeriesPaint(idx, SELECTED_SERIES);
}
}
@Override
public void chartMouseMoved(ChartMouseEvent cme) {
int viewX = cme.getTrigger().getX();
XYPlot plot = (XYPlot) chart.getPlot();
ValueAxis xAxis = plot.getDomainAxis();
Rectangle2D dataArea = cp.getScreenDataArea();
RectangleEdge xAxisEdge = plot.getDomainAxisEdge();
double domainX = 0.0;
double domainY = 0.0;
double xx = xAxis.java2DToValue(viewX, dataArea, xAxisEdge);
for (int i = 0; i < plot.getDataset().getItemCount(0); i++) {
double dataX = plot.getDataset().getXValue(0, i);
if (dataX >= xx) {
domainX = dataX;
domainY = plot.getDataset().getYValue(0, i);
hud.setXLabel(X_AXIS_DATE_FORMAT.format(new Date((long) domainX)));
hud.setYLabel(Double.toString(domainY));
break;
}
}
setCrosshairLocation(domainX, domainY);
}
protected void setCrosshairLocation(double x, double y) {
Crosshair domainCrosshair;
Crosshair rangeCrosshair;
if (crosshairOverlay == null) {
crosshairOverlay = new CrosshairOverlay();
domainCrosshair = new Crosshair();
domainCrosshair.setPaint(ChartColor.LIGHT_BLUE);
domainCrosshair.setStroke(dashed);
domainCrosshair.setVisible(true);
crosshairOverlay.addDomainCrosshair(domainCrosshair);
cp.addOverlay(crosshairOverlay);
} else {
domainCrosshair = (Crosshair) crosshairOverlay.getDomainCrosshairs().get(0);
}
domainCrosshair.setValue(x);
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
}
@Override
public void keyReleased(KeyEvent e) {
if ((e.getKeyCode() == KeyEvent.VK_DELETE ||
e.getKeyCode() == KeyEvent.VK_BACK_SPACE) &&
lastDataset != null) {
// chart.getXYPlot().getDataset()
}
}
}