package gov.nasa.arc.mct.fastplot.bridge.controls; import gov.nasa.arc.mct.fastplot.bridge.AbstractPlottingPackage; import gov.nasa.arc.mct.fastplot.bridge.PlotAbstraction; import java.awt.KeyEventDispatcher; import java.awt.KeyboardFocusManager; import java.awt.event.KeyEvent; import javax.swing.event.AncestorEvent; import javax.swing.event.AncestorListener; /** * Dispatches key events directly to plot local controls, regardless of focus (but only if the * mouse is hovering over the plot). This is an alternative to other keyboard input strategies * in Swing (KeyListener, InputMap) which only apply when components have focus, whose usage * may require a lot of extra code to make sure that the plot has focus whenever the user might * expect it to. * * Usage note: It is advisable to attach this as an AncestorListener to a relevant JComponent * instead of registering it as a KeyEventDispatcher directly. When acting as an * AncestorListener, this will register and remove itself as a KeyEventDispatcher automatically * when the component is added or removed from the Swing hierarchy. This helps ensure that * stale references do not remain in the KeyboardFocusManager, which is global (so out-dated * dispatchers which are not removed present memory leaks.) * * @author vwoeltje */ public class LocalControlKeyEventDispatcher implements KeyEventDispatcher, AncestorListener { private PlotAbstraction abstraction; public LocalControlKeyEventDispatcher(PlotAbstraction abstraction) { super(); this.abstraction = abstraction; } @Override public boolean dispatchKeyEvent(KeyEvent event) { int id = event.getID(); /* Any PRESSED or RELEASED events should be reported to local controls */ if (id == KeyEvent.KEY_PRESSED || id == KeyEvent.KEY_RELEASED) { boolean pressed = id == KeyEvent.KEY_PRESSED; for (AbstractPlottingPackage p : abstraction.getSubPlots()) { // Report all key released events, or any event in the plot area if (!pressed || !p.getPlotActionListener().isMouseOutsideOfPlotArea()) { p.getLocalControlsManager().informKeyState(event.getKeyCode(), pressed); } } } return false; /* * Note that this is not particularly efficient; all key presses get forwarded to all * plots, which is potentially a lot of plots. It may make more sense to build a map * of keycodes -> interested local control managers at the time of instantiation. * But, this risks bugs if the map becomes out-of-date, and may also require additions * to related interfaces to allow these key bindings to be inferred or registered. */ } @Override public void ancestorRemoved(AncestorEvent e) { KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventDispatcher(this); } @Override public void ancestorAdded(AncestorEvent e) { KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(this); } @Override public void ancestorMoved(AncestorEvent arg0) { } }