package gov.nasa.arc.mct.fastplot.bridge.controls; import gov.nasa.arc.mct.fastplot.bridge.AbstractAxis; import gov.nasa.arc.mct.fastplot.bridge.AbstractAxisBoundManager; import gov.nasa.arc.mct.fastplot.bridge.PlotConstants.LimitAlarmState; import gov.nasa.arc.mct.fastplot.bridge.PlotObserver; import gov.nasa.arc.mct.fastplot.bridge.PlotSubject; import gov.nasa.arc.mct.fastplot.view.IconLoader.Icons; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; import javax.swing.JComponent; import javax.swing.SpringLayout; /** * A boundary arrow ("purple arrow") gives the user a visual indicator about whether or not * out-of-bounds data has flowed; clicking this indicator will toggle between expanding the * axis to show out of bounds data, and collapsing back to the original state. * * Purple arrows states are: * - (no arrow): No out of bounds data in current time span * - Solid: Out of bounds data within the current plot time span (not yet seen) * - Translucent: Currently expanded to show out-of-bounds data (clicking collapses) * - Outlined: Out of bounds data within the current plot time span (but it's been seen) * * @author vwoeltje */ public class BoundaryArrow extends AbstractPlotLocalControl implements ActionListener, PlotObserver { private static final long serialVersionUID = 5672919575563084898L; private LimitAlarmState currentState; private AbstractAxisBoundManager boundary; private Map<LimitAlarmState, JComponent> boundaryIcons = new HashMap<LimitAlarmState, JComponent>(); /** * Create a new boundary arrow. * @param boundary the boundary which this arrow is used to represent / interact with * @param isStart whether or not this boundary is at the start of an axis */ public BoundaryArrow(AbstractAxisBoundManager boundary) { super(); setLayout(new GridLayout()); this.boundary = boundary; currentState = LimitAlarmState.NO_ALARM; initializeButtons(); updateAppearance(boundary.getState()); setBorder(null); } private void updateAppearance(LimitAlarmState state) { if (currentState != state) { if (state == LimitAlarmState.NO_ALARM) { setVisible(false); } else if (state != null) { removeAll(); add(boundaryIcons.get(state)); setVisible(true); } currentState = state; } } @Override public Collection<AttachmentLocation> getDesiredAttachmentLocations() { Collection<AttachmentLocation> attachments = new ArrayList<AttachmentLocation>(); switch (boundary.getAxis().getVisibleOrientation()) { case HORIZONTAL: attachments.add(new AttachmentLocation(SpringLayout.VERTICAL_CENTER)); attachments.add(new AttachmentLocation(boundary.isStart() ? SpringLayout.WEST : SpringLayout.EAST)); break; case VERTICAL: attachments.add(new AttachmentLocation(SpringLayout.HORIZONTAL_CENTER)); attachments.add(new AttachmentLocation(boundary.isStart() ? SpringLayout.SOUTH : SpringLayout.NORTH)); break; } return attachments; } @Override public PlotObserver getPlotObserver() { return this; } private void initializeButtons() { switch (boundary.getAxis().getVisibleOrientation()) { case HORIZONTAL: boundaryIcons.put(LimitAlarmState.ALARM_RAISED, makeButton(boundary.isStart() ? Icons.PLOT_LEFT_ARROW_SOLID_ICON : Icons.PLOT_RIGHT_ARROW_SOLID_ICON, this, "ShowAllData")); boundaryIcons.put(LimitAlarmState.ALARM_CLOSED_BY_USER, makeButton(boundary.isStart() ? Icons.PLOT_LEFT_ARROW_HOLLOW_ICON : Icons.PLOT_RIGHT_ARROW_HOLLOW_ICON, this, "ShowAllDataAgain")); boundaryIcons.put(LimitAlarmState.ALARM_OPENED_BY_USER, makeButton(!boundary.isStart() ? Icons.PLOT_LEFT_ARROW_TRANSLUCENT_ICON : Icons.PLOT_RIGHT_ARROW_TRANSLUCENT_ICON, this, "HideOOBData")); break; case VERTICAL: boundaryIcons.put(LimitAlarmState.ALARM_RAISED, makeButton(boundary.isStart() ? Icons.PLOT_DOWN_ARROW_SOLID_ICON : Icons.PLOT_UP_ARROW_SOLID_ICON, this, "ShowAllData")); boundaryIcons.put(LimitAlarmState.ALARM_CLOSED_BY_USER, makeButton(boundary.isStart() ? Icons.PLOT_DOWN_ARROW_HOLLOW_ICON : Icons.PLOT_UP_ARROW_HOLLOW_ICON, this, "ShowAllDataAgain")); boundaryIcons.put(LimitAlarmState.ALARM_OPENED_BY_USER, makeButton(!boundary.isStart() ? Icons.PLOT_DOWN_ARROW_TRANSLUCENT_ICON : Icons.PLOT_UP_ARROW_TRANSLUCENT_ICON, this, "HideOOBData")); break; } } @Override public void actionPerformed(ActionEvent event) { switch (boundary.getState()) { case ALARM_RAISED: case ALARM_CLOSED_BY_USER: boundary.expand(); break; case ALARM_OPENED_BY_USER: boundary.collapse(); break; } updateAppearance(boundary.getState()); } @Override public void updateTimeAxis(PlotSubject subject, long startTime, long endTime) { // TODO Auto-generated method stub } @Override public void plotAxisChanged(PlotSubject subject, AbstractAxis axis) { // TODO Auto-generated method stub } @Override public void dataPlotted() { updateAppearance(boundary.getState()); } }