package org.opentrafficsim.swing.graphs;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.swing.ButtonGroup;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JMenu;
import javax.swing.JPopupMenu;
import javax.swing.JRadioButtonMenuItem;
import org.opentrafficsim.draw.graphs.AbstractContourPlot;
import org.opentrafficsim.draw.graphs.AbstractSpaceTimePlot;
import org.opentrafficsim.draw.graphs.ContourDataSource.Dimension;
/**
* Embed a ContourPlot in a Swing JPanel.
*
* @author Alexander Verbraeck
* @author Peter Knoppers
* @author Wouter Schakel
*/
public class SwingContourPlot extends SwingSpaceTimePlot
{
/** */
private static final long serialVersionUID = 20190823L;
/** Map to set time granularity. */
private Map timeGranularityButtons;
/** Map to set space granularity. */
private Map spaceGranularityButtons;
/** Check box for smoothing. */
private JCheckBoxMenuItem smoothCheckBox;
/** Check box for interpolation. */
private JCheckBoxMenuItem interpolateCheckBox;
/**
* Create a new SwingContourPlot with embedded plot.
* @param plot AbstractSpaceTimePlot; the plot to embed
*/
public SwingContourPlot(final AbstractSpaceTimePlot plot)
{
super(plot);
}
/** {@inheritDoc} */
@Override
protected void addPopUpMenuItems(final JPopupMenu popupMenu)
{
timeGranularityButtons = new LinkedHashMap<>();
spaceGranularityButtons = new LinkedHashMap<>();
super.addPopUpMenuItems(popupMenu);
JMenu spaceGranularityMenu = buildMenu("Distance granularity", "%.0f m", 1000, "%.0f km", "setSpaceGranularity",
getPlot().getDataPool().getGranularities(Dimension.DISTANCE),
getPlot().getDataPool().getGranularity(Dimension.DISTANCE), this.spaceGranularityButtons);
popupMenu.insert(spaceGranularityMenu, 0);
JMenu timeGranularityMenu = buildMenu("Time granularity", "%.0f s", 60.0, "%.0f min", "setTimeGranularity",
getPlot().getDataPool().getGranularities(Dimension.TIME),
getPlot().getDataPool().getGranularity(Dimension.TIME), this.timeGranularityButtons);
popupMenu.insert(timeGranularityMenu, 1);
this.smoothCheckBox = new JCheckBoxMenuItem("Adaptive smoothing method", false);
this.smoothCheckBox.addActionListener(new ActionListener()
{
/** {@inheritDoc} */
@Override
public void actionPerformed(final ActionEvent e)
{
getPlot().getDataPool().setSmooth(((JCheckBoxMenuItem) e.getSource()).isSelected());
getPlot().notifyPlotChange();
}
});
popupMenu.insert(this.smoothCheckBox, 2);
this.interpolateCheckBox = new JCheckBoxMenuItem("Bilinear interpolation", true);
this.interpolateCheckBox.addActionListener(new ActionListener()
{
/** {@inheritDoc} */
@Override
public void actionPerformed(final ActionEvent e)
{
boolean interpolate = ((JCheckBoxMenuItem) e.getSource()).isSelected();
getPlot().getBlockRenderer().setInterpolate(interpolate);
getPlot().getDataPool().setInterpolate(interpolate);
getPlot().notifyPlotChange();
}
});
popupMenu.insert(this.interpolateCheckBox, 3);
}
/**
* Create a JMenu to let the user set the granularity.
* @param menuName String; caption for the new JMenu
* @param format1 String; format string for the values in the items under the new JMenu, below formatValue
* @param formatValue double; format value
* @param format2 String; format string for the values in the items under the new JMenu, above and equal to formatValue
* @param command String; prefix for the actionCommand of the items under the new JMenu
* @param values double[]; array of values to be formatted using the format strings to yield the items under the new JMenu
* @param initialValue double; the currently selected value (used to put the bullet on the correct item)
* @param granularityButtons Map<JRadioButtonMenuItem, Double>; map in to which buttons should be added
* @return JMenu with JRadioMenuItems for the values and a bullet on the currentValue item
*/
private JMenu buildMenu(final String menuName, final String format1, final double formatValue, final String format2,
final String command, final double[] values, final double initialValue,
final Map granularityButtons)
{
JMenu result = new JMenu(menuName);
ButtonGroup group = new ButtonGroup();
for (double value : values)
{
JRadioButtonMenuItem item = new JRadioButtonMenuItem(
String.format(value < formatValue ? format1 : format2, value < formatValue ? value : value / formatValue));
granularityButtons.put(item, value);
item.setSelected(value == initialValue);
item.setActionCommand(command);
item.addActionListener(new ActionListener()
{
/** {@inheritDoc} */
@Override
public void actionPerformed(final ActionEvent actionEvent)
{
if (command.equalsIgnoreCase("setSpaceGranularity"))
{
double granularity = spaceGranularityButtons.get(actionEvent.getSource());
getPlot().getDataPool().setGranularity(Dimension.DISTANCE, granularity);
}
else if (command.equalsIgnoreCase("setTimeGranularity"))
{
double granularity = timeGranularityButtons.get(actionEvent.getSource());
getPlot().getDataPool().setGranularity(Dimension.TIME, granularity);
}
else
{
throw new RuntimeException("Unknown ActionEvent");
}
}
});
result.add(item);
group.add(item);
}
return result;
}
/** {@inheritDoc} */
@Override
public AbstractContourPlot> getPlot()
{
return (AbstractContourPlot>) super.getPlot();
}
/**
* Sets the correct space granularity radio button to selected. This is done from a {@code DataPool} to keep multiple plots
* consistent.
* @param granularity double; space granularity
*/
protected final void setSpaceGranularityRadioButton(final double granularity)
{
getPlot().setSpaceGranularity(granularity);
for (JRadioButtonMenuItem button : this.spaceGranularityButtons.keySet())
{
button.setSelected(this.spaceGranularityButtons.get(button) == granularity);
}
}
/**
* Sets the correct time granularity radio button to selected. This is done from a {@code DataPool} to keep multiple plots
* consistent.
* @param granularity double; time granularity
*/
protected final void setTimeGranularityRadioButton(final double granularity)
{
getPlot().setTimeGranularity(granularity);
for (JRadioButtonMenuItem button : this.timeGranularityButtons.keySet())
{
button.setSelected(this.timeGranularityButtons.get(button) == granularity);
}
}
/**
* Sets the check box for smooth rendering. This is done from a {@code DataPool} to keep multiple plots consistent.
* @param smooth boolean; selected or not
*/
protected final void setSmoothing(final boolean smooth)
{
this.smoothCheckBox.setSelected(smooth);
}
/**
* Sets the check box for interpolated rendering and block renderer setting. This is done from a {@code DataPool} to keep
* multiple plots consistent.
* @param interpolate boolean; selected or not
*/
protected final void setInterpolation(final boolean interpolate)
{
getPlot().setInterpolation(interpolate);
this.interpolateCheckBox.setSelected(interpolate);
}
}