From 5488f7814060cb976120221fbf0bdef18b115a3d Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 22 Jan 2013 11:31:48 -0800 Subject: [PATCH] Added documentation to local controls classes in fastPlot. Package gov.nasa.arc.mct.fastplot.bridge.controls introduces several classes/interfaces for dealing with local control elements in a uniform way; added documentation of the role of these classes. --- .../arc/mct/fastplot/bridge/PlotView.java | 9 +-- .../controls/AbstractPanZoomControls.java | 19 ++++-- .../controls/AbstractPlotLocalControl.java | 15 +---- .../AbstractPlotLocalControlsManager.java | 27 +++++++- ...ervableAxis.java => ControllableAxis.java} | 4 +- .../bridge/controls/CornerResetButton.java | 61 ++++++++++++++++--- .../LocalControlKeyEventDispatcher.java | 26 +++++++- .../fastplot/bridge/controls/PanControls.java | 12 +++- .../bridge/controls/ZoomControls.java | 10 +++ .../fastplot/view/PlotViewManifestation.java | 24 -------- 10 files changed, 147 insertions(+), 60 deletions(-) rename fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/controls/{ObservableAxis.java => ControllableAxis.java} (95%) diff --git a/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/PlotView.java b/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/PlotView.java index aa0b5f1e..97462174 100644 --- a/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/PlotView.java +++ b/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/PlotView.java @@ -30,7 +30,7 @@ import gov.nasa.arc.mct.fastplot.bridge.PlotConstants.YAxisMaximumLocationSetting; import gov.nasa.arc.mct.fastplot.bridge.controls.CornerResetButton; import gov.nasa.arc.mct.fastplot.bridge.controls.LocalControlKeyEventDispatcher; -import gov.nasa.arc.mct.fastplot.bridge.controls.ObservableAxis; +import gov.nasa.arc.mct.fastplot.bridge.controls.ControllableAxis; import gov.nasa.arc.mct.fastplot.bridge.controls.PanControls; import gov.nasa.arc.mct.fastplot.bridge.controls.ZoomControls; import gov.nasa.arc.mct.fastplot.settings.LineSettings; @@ -772,6 +772,7 @@ public void run() { timer.schedule(updateTimeBoundsTask, 0, 1000); } }); + /* Make sure key events get dispatched to local controls (which enable for Alt/Ctrl/etc...) */ plotPanel.addAncestorListener(new LocalControlKeyEventDispatcher(this)); GridBagLayout layout = new StackPlotLayout(this); plotPanel.setLayout(layout); @@ -803,17 +804,17 @@ public void run() { this, plotLabelingAlgorithm); // TODO: Move control attachment elsewhere - List observableAxes = new ArrayList(); + List observableAxes = new ArrayList(); for (AbstractAxis axis : newPlot.getAxes()) { if (axis != null && axis.getVisibleOrientation() != null) { - ObservableAxis a = new ObservableAxis(newPlot, axis); + ControllableAxis a = new ControllableAxis(newPlot, axis); observableAxes.add(a); newPlot.attachLocalControl(new PanControls(a)); newPlot.attachLocalControl(new ZoomControls(a)); newPlot.attachLocalControl(new CornerResetButton(a)); } } - newPlot.attachLocalControl(new CornerResetButton(observableAxes.toArray(new ObservableAxis[observableAxes.size()]))); + newPlot.attachLocalControl(new CornerResetButton(observableAxes.toArray(new ControllableAxis[observableAxes.size()]))); newPlot.setPlotLabelingAlgorithm(plotLabelingAlgorithm); subPlots.add(newPlot); diff --git a/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/controls/AbstractPanZoomControls.java b/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/controls/AbstractPanZoomControls.java index d33c13eb..dfe2cb51 100644 --- a/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/controls/AbstractPanZoomControls.java +++ b/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/controls/AbstractPanZoomControls.java @@ -1,14 +1,12 @@ package gov.nasa.arc.mct.fastplot.bridge.controls; import gov.nasa.arc.mct.fastplot.bridge.AbstractAxis; -import gov.nasa.arc.mct.fastplot.bridge.PlotConstants; -import gov.nasa.arc.mct.fastplot.bridge.PlotObserver; import gov.nasa.arc.mct.fastplot.bridge.AbstractAxis.AxisVisibleOrientation; +import gov.nasa.arc.mct.fastplot.bridge.PlotObserver; import gov.nasa.arc.mct.fastplot.view.IconLoader.Icons; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.awt.event.KeyEvent; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -40,6 +38,11 @@ public abstract class AbstractPanZoomControls extends AbstractPlotLocalControl i private boolean keyState = false; private boolean mouseState = false; + /** + * Create controls for the specified plot axis. The axis will be used to determine the orientation + * of controls (horizontal or vertical), and will receive updates when controls are clicked. + * @param axis + */ public AbstractPanZoomControls(AbstractAxis axis) { super(); this.axis = axis; @@ -67,10 +70,16 @@ public AbstractPanZoomControls(AbstractAxis axis) { /** * Apply whatever adjustment this control performs (panning or zooming) - * The "less" argument indicates whether or not this + * The "less" argument indicates whether or not this adjustment goes toward the bottom-left. + * + * Note that currentSpan is presumed to be calculated as getEnd-getStart for the axis; so, + * the sign will be negative if the axes have been inverted (i.e. "max at left"). Implementing + * classes may use this sign (implicitly or explicitly) to adjust the axis in the correct + * direction. * + * @param axis the axis to update * @param currentSpan the current axis span - * @param less true if the "les" + * @param less */ public abstract void adjustAxis(AbstractAxis axis, double currentSpan, boolean less); diff --git a/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/controls/AbstractPlotLocalControl.java b/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/controls/AbstractPlotLocalControl.java index 51ca4e8f..c64f75af 100644 --- a/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/controls/AbstractPlotLocalControl.java +++ b/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/controls/AbstractPlotLocalControl.java @@ -7,14 +7,12 @@ import gov.nasa.arc.mct.fastplot.view.IconLoader; import java.awt.event.ActionListener; -import java.util.Arrays; import java.util.Collection; import java.util.ResourceBundle; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JPanel; -import javax.swing.SpringLayout; import javax.swing.border.Border; /** @@ -22,6 +20,8 @@ * plot view, used to make immediate changes to what is being shown (as opposed to broader * changes to the view). * + * @see gov.nasa.arc.mct.fastplot.bridge.AbstractPlottingPackage#attachLocalControl(AbstractPlotLocalControl) + * * @author vwoeltje */ public abstract class AbstractPlotLocalControl extends JPanel { @@ -29,22 +29,13 @@ public abstract class AbstractPlotLocalControl extends JPanel { private static final ResourceBundle BUNDLE = ResourceBundle.getBundle(PlotLocalControlsManager.class.getName().substring(0, PlotLocalControlsManager.class.getName().lastIndexOf("."))+".Bundle"); - - + private static final Border BUTTON_BORDER = BorderFactory.createEmptyBorder( PlotConstants.ARROW_BUTTON_BORDER_STYLE_BOTTOM, PlotConstants.ARROW_BUTTON_BORDER_STYLE_LEFT, PlotConstants.ARROW_BUTTON_BORDER_STYLE_BOTTOM, PlotConstants.ARROW_BUTTON_BORDER_STYLE_RIGHT); - public static final Collection FILL_ATTACHMENT = - Arrays.asList( - new AttachmentLocation(SpringLayout.WEST, SpringLayout.WEST, 0), - new AttachmentLocation(SpringLayout.EAST, SpringLayout.EAST, 0), - new AttachmentLocation(SpringLayout.NORTH, SpringLayout.NORTH, 0), - new AttachmentLocation(SpringLayout.SOUTH, SpringLayout.SOUTH, 0) - ); - /** * Controls are attached to one specific plot, represented by this object */ diff --git a/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/controls/AbstractPlotLocalControlsManager.java b/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/controls/AbstractPlotLocalControlsManager.java index 1c38a456..81c81f28 100644 --- a/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/controls/AbstractPlotLocalControlsManager.java +++ b/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/controls/AbstractPlotLocalControlsManager.java @@ -1,6 +1,31 @@ package gov.nasa.arc.mct.fastplot.bridge.controls; -public interface AbstractPlotLocalControlsManager { +/** + * Manages the local controls for a given plot. Primarily used to communicate user + * interactions to specific controls when the control is not able to listen for them + * locally in the Swing hierarchy (specifically, many controls are interested in either + * whether or not the mouse is over the plot area, or need to listen for key events + * even when they don't have focus.) + * + * Note: May consider removing this and simply return a Collection + * from AbstractPlottingPackage to simplify API. (The current implementation + * permits some cross-compatibility with the older PlotLocalControlManager.) + * + * @see gov.nasa.arc.mct.fastplot.bridge.AbstractPlottingPackage#getLocalControlsManager() + * + * @author vwoeltje + */ +public interface AbstractPlotLocalControlsManager { + /** + * Notify local controls that a specific key has been pressed or released. + * @param key the key code pressed/released (one of KeyEvent.VK_*) + * @param pressed true if press; false if released + */ public void informKeyState(int key, boolean pressed); + + /** + * Notify local controls of changes to the mouse position with regard to the plot + * @param inPlotArea true if hovering over plot; false if mouse has left + */ public void informMouseHover(boolean inPlotArea); } diff --git a/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/controls/ObservableAxis.java b/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/controls/ControllableAxis.java similarity index 95% rename from fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/controls/ObservableAxis.java rename to fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/controls/ControllableAxis.java index b6d4a292..ac04c96e 100644 --- a/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/controls/ObservableAxis.java +++ b/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/controls/ControllableAxis.java @@ -10,7 +10,7 @@ * @author vwoeltje * */ -public class ObservableAxis implements AbstractAxis { +public class ControllableAxis implements AbstractAxis { private AbstractAxis axis; private PlotSubject subject; @@ -18,7 +18,7 @@ public class ObservableAxis implements AbstractAxis { private double recordedStart; private double recordedEnd; - public ObservableAxis(PlotSubject subject, AbstractAxis axis) { + public ControllableAxis(PlotSubject subject, AbstractAxis axis) { super(); this.axis = axis; this.subject = subject; diff --git a/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/controls/CornerResetButton.java b/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/controls/CornerResetButton.java index 301e59fd..b727ed8b 100644 --- a/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/controls/CornerResetButton.java +++ b/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/controls/CornerResetButton.java @@ -16,12 +16,33 @@ import javax.swing.SpringLayout; +/** + * A CornerResetButton checks for changes made by local controls, and presents a button + * for the user to click in order to undo these changes and restore the previous axis + * state. + * + * @author vwoeltje + * + */ public class CornerResetButton extends AbstractPlotLocalControl implements PlotObserver, ActionListener { private static final long serialVersionUID = -348727120749498680L; - private Collection managedAxes = new ArrayList(); + /** + * The axes that this reset button looks at and may reset. + */ + private Collection managedAxes = new ArrayList(); - public CornerResetButton(ObservableAxis... axes) { + /** + * Create a new corner reset button; this will monitor the provided axes for local + * changes and make a button visible as appropriate; when clicked, this button will reset + * these all monitored axes. + * + * Note that the shape and position of this button will be inferred by examining + * the list of provided axes. + * + * @param axes the axes to be monitored and reset by this button + */ + public CornerResetButton(ControllableAxis... axes) { super(); setLayout(new GridLayout()); Collections.addAll(managedAxes, axes); @@ -30,6 +51,13 @@ public CornerResetButton(ObservableAxis... axes) { setBorder(null); } + /** + * Get the attachment location for this control. + * + * X-Axis reset button appears bottom-right; + * Y-Axis reset button appears top-left; + * X & Y axis reset button appears bottom-left. + */ @Override public Collection getDesiredAttachmentLocations() { String verticalEdge = isManaged(AxisVisibleOrientation.VERTICAL) ? @@ -49,14 +77,14 @@ public PlotObserver getPlotObserver() { @Override public void updateTimeAxis(PlotSubject subject, long startTime, long endTime) { - // TODO Auto-generated method stub - } @Override public void plotAxisChanged(PlotSubject subject, AbstractAxis axis) { + // When the plot axis has changed, check to see if those changes are local boolean dirty = true; - for (ObservableAxis a : managedAxes) { + for (ControllableAxis a : managedAxes) { + // Only display if ALL axes have changed dirty &= a.isDirty(); } setVisible(dirty); @@ -64,13 +92,20 @@ public void plotAxisChanged(PlotSubject subject, AbstractAxis axis) { @Override public void actionPerformed(ActionEvent e) { - for (ObservableAxis a : managedAxes) { + // Reset all axes when clicked + for (ControllableAxis a : managedAxes) { a.reset(); } } - private boolean isManaged(AxisVisibleOrientation o) { - for (ObservableAxis axis : managedAxes) { + /** + * Utility method to determine if a given orientation (horizontal or vertical) is + * among the axes being managed. + * @param o + * @return + */ + private boolean isManaged(AxisVisibleOrientation o) { + for (ControllableAxis axis : managedAxes) { if (axis.getVisibleOrientation() == o) { return true; } @@ -78,6 +113,10 @@ private boolean isManaged(AxisVisibleOrientation o) { return false; } + /** + * Choose the icon for this button, based on the orientation of the axes managed. + * @return + */ private Icons chooseIcon() { Icons[] icons = { Icons.PLOT_CORNER_RESET_BUTTON_TOP_LEFT_GREY, Icons.PLOT_CORNER_RESET_BUTTON_TOP_RIGHT_GREY, Icons.PLOT_CORNER_RESET_BUTTON_BOTTOM_LEFT_GREY, Icons.PLOT_CORNER_RESET_BUTTON_BOTTOM_RIGHT_GREY }; @@ -85,7 +124,11 @@ private Icons chooseIcon() { (isManaged(AxisVisibleOrientation.VERTICAL ) ? 0 : 1); return icons[index]; } - + + /** + * Choose the name for this button, based on the orientation of the axes managed. + * @return + */ private String chooseName() { String[] names = { "TopLeftCornerButton", "TopRightCornerButton", "BottomLeftCornerButton", "BottomRightCornerButton" }; diff --git a/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/controls/LocalControlKeyEventDispatcher.java b/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/controls/LocalControlKeyEventDispatcher.java index 0a5ed320..58938ef8 100644 --- a/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/controls/LocalControlKeyEventDispatcher.java +++ b/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/controls/LocalControlKeyEventDispatcher.java @@ -10,6 +10,22 @@ 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; @@ -21,6 +37,7 @@ public LocalControlKeyEventDispatcher(PlotAbstraction 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()) { @@ -31,6 +48,13 @@ public boolean dispatchKeyEvent(KeyEvent event) { } } 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. + */ } @@ -48,8 +72,6 @@ public void ancestorAdded(AncestorEvent e) { @Override public void ancestorMoved(AncestorEvent arg0) { - // TODO Auto-generated method stub - } } diff --git a/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/controls/PanControls.java b/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/controls/PanControls.java index 7f8524aa..8a616431 100644 --- a/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/controls/PanControls.java +++ b/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/controls/PanControls.java @@ -7,15 +7,25 @@ import java.awt.event.KeyEvent; +/** + * Buttons to pan along an axis. + * + * @author vwoeltje + * + */ public class PanControls extends AbstractPanZoomControls { private static final long serialVersionUID = 3970100144412350694L; + /** + * Create pan controls for the specified axis. + * @param axis + */ public PanControls(AbstractAxis axis) { super(axis); } @Override - public void adjustAxis(AbstractAxis axis, double currentSpan, boolean less) { + public void adjustAxis(AbstractAxis axis, double currentSpan, boolean less) { axis.shift(currentSpan * (PlotConstants.PANNING_PERCENTAGE / 100.) * (less ? -1 : 1)); } diff --git a/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/controls/ZoomControls.java b/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/controls/ZoomControls.java index 3ae35d90..965aa7f5 100644 --- a/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/controls/ZoomControls.java +++ b/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/bridge/controls/ZoomControls.java @@ -7,9 +7,19 @@ import java.awt.event.KeyEvent; +/** + * Buttons to zoom in/out on an axis. + * + * @author vwoeltje + * + */ public class ZoomControls extends AbstractPanZoomControls { private static final long serialVersionUID = 3970100144412350694L; + /** + * Create pan controls for the specified axis. + * @param axis + */ public ZoomControls(AbstractAxis axis) { super(axis); } diff --git a/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/view/PlotViewManifestation.java b/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/view/PlotViewManifestation.java index 084d2302..093290a8 100644 --- a/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/view/PlotViewManifestation.java +++ b/fastPlotViews/src/main/java/gov/nasa/arc/mct/fastplot/view/PlotViewManifestation.java @@ -95,30 +95,6 @@ public class PlotViewManifestation extends FeedView implements RenderingCallback JComponent controlPanel; public static final String VIEW_ROLE_NAME = "Plot"; - /** This listens to key events for the plot view and all sub-components so it can forward modifier key presses and releases to the local controls managers. */ - private KeyListener keyListener = new KeyListener() { - @Override - public void keyTyped(KeyEvent e) { - } - - @Override - public void keyReleased(KeyEvent e) { - for (AbstractPlottingPackage p : thePlot.getSubPlots()) { - p.getLocalControlsManager().informKeyState(e.getKeyCode(), false); - } - } - - - @Override - public void keyPressed(KeyEvent e) { - for (AbstractPlottingPackage p : thePlot.getSubPlots()) { - if (!p.getPlotActionListener().isMouseOutsideOfPlotArea()) { - p.getLocalControlsManager().informKeyState(e.getKeyCode(), true); - } - } - } - }; - public PlotViewManifestation(AbstractComponent component, ViewInfo vi) { super(component,vi);