package au.gov.amsa.geo.distance; import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.event.ComponentEvent; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.io.File; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.SwingUtilities; import org.apache.log4j.Logger; import rx.Observable; import au.gov.amsa.geo.distance.DistanceTravelledCalculator.CalculationResult; import au.gov.amsa.geo.model.Bounds; import au.gov.amsa.geo.model.Options; /** * Swing application that allows viewing of traffic density plots. Supports * zooming via double-click. * */ public class DisplayPanel extends JPanel { private static final long serialVersionUID = 7844558863774822599L; private static Logger log = Logger.getLogger(DisplayPanel.class); private Options options; private int numStandardDeviations; private CalculationResult calculationResult; public DisplayPanel(int numberStandardDeviations, final CellsUpdater updater) { this.numStandardDeviations = numberStandardDeviations; setPreferredSize(java.awt.Toolkit.getDefaultToolkit().getScreenSize()); setBackground(Color.white); setFocusable(true); addKeyListener(createKeyListener()); addMouseListener(createMouseListener(updater)); } public void setCalculationResult(CalculationResult calculationResult, Options options) { this.calculationResult = calculationResult; this.options = options; repaint(); } @Override protected void paintComponent(Graphics gOld) { super.paintComponent(gOld); Graphics2D g = (Graphics2D) gOld; Renderer.paintAll(g, options, numStandardDeviations, getWidth(), getHeight(), calculationResult, true, true); } public static interface CellsUpdater { void update(DisplayPanel display, Bounds bounds); } private KeyListener createKeyListener() { return new KeyListener() { @Override public void keyTyped(KeyEvent e) { } @Override public void keyPressed(KeyEvent e) { int keyCode = e.getKeyCode(); if (keyCode == 49) { numStandardDeviations = 1; repaint(); } else if (keyCode == 50) { numStandardDeviations = 2; repaint(); } else if (keyCode == 51) { numStandardDeviations = 3; repaint(); } } @Override public void keyReleased(KeyEvent e) { } }; } private MouseListener createMouseListener(final CellsUpdater updater) { return new MouseListener() { @Override public void mouseClicked(final MouseEvent e) { if (e.getClickCount() == 2) { log.info("double clicked"); Thread t = new Thread(new Runnable() { @Override public void run() { log.info("updating cells"); double propX = (double) e.getX() / getWidth(); double propY = (double) e.getY() / getHeight(); double zoomFactor = 0.5; Bounds b = options.getBounds(); double topLeftLat = b.getTopLeftLat() - propY * (b.getHeightDegrees()) + zoomFactor * b.getHeightDegrees() / 2; double topLeftLon = b.getTopLeftLon() + propX * b.getWidthDegrees() - zoomFactor * b.getWidthDegrees() / 2; double bottomRightLat = topLeftLat - zoomFactor * b.getHeightDegrees(); double bottomRightLon = topLeftLon + zoomFactor * b.getWidthDegrees(); updater.update(DisplayPanel.this, new Bounds( topLeftLat, topLeftLon, bottomRightLat, bottomRightLon)); repaint(); } }); t.start(); } } @Override public void mousePressed(MouseEvent e) { } @Override public void mouseReleased(MouseEvent e) { } @Override public void mouseEntered(MouseEvent e) { } @Override public void mouseExited(MouseEvent e) { } }; } public void run() { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { final JFrame f = new JFrame("Vessel Traffic Density"); // Sets the behavior for when the window is closed f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Add a layout manager so that the button is not placed on top // of the // label f.setLayout(new FlowLayout()); // // Add a label and a button // f.add(new JLabel("Hello, world!")); // f.add(new JButton("Press me!")); f.add(DisplayPanel.this); // Arrange the components inside the window f.pack(); // By default, the window is not visible. Make it visible. f.setVisible(true); f.addComponentListener(new java.awt.event.ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { DisplayPanel.this.setPreferredSize(new Dimension(f .getWidth(), f.getHeight())); } }); } }); } public static void displayGui(final Observable<File> files, final Options options, final CalculationResult calculationResult) { final DisplayPanel display = new DisplayPanel(2, new CellsUpdater() { @Override public void update(DisplayPanel display, Bounds bounds) { // decrease cell size by 0.8 beyond the normal proportional // decrease double cellSizeDegrees = bounds.getWidthDegrees() / options.getBounds().getWidthDegrees() * options.getCellSizeDegreesAsDouble() * 0.8; Options o2 = Options.builder().cellSizeDegrees(cellSizeDegrees) .bounds(bounds).build(); display.setCalculationResult(DistanceTravelledCalculator .calculateTrafficDensity(o2, files), o2); } }); display.setCalculationResult(calculationResult, options); display.run(); } }