/*******************************************************************************
* Mission Control Technologies, Copyright (c) 2009-2012, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* The MCT platform is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* MCT includes source code licensed under additional open source licenses. See
* the MCT Open Source Licenses file included with this distribution or the About
* MCT Licenses dialog available at runtime from the MCT Help menu for additional
* information.
*******************************************************************************/
package gov.nasa.arc.mct.fastplot.bridge;
import gov.nasa.arc.mct.fastplot.bridge.PlotConstants.AxisOrientationSetting;
import gov.nasa.arc.mct.fastplot.bridge.PlotConstants.NonTimeAxisSubsequentBoundsSetting;
import gov.nasa.arc.mct.fastplot.bridge.PlotConstants.TimeAxisSubsequentBoundsSetting;
import gov.nasa.arc.mct.fastplot.bridge.PlotConstants.XAxisMaximumLocationSetting;
import gov.nasa.arc.mct.fastplot.bridge.PlotConstants.YAxisMaximumLocationSetting;
import gov.nasa.arc.mct.fastplot.utils.TimeFormatUtils;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Rectangle;
import java.text.FieldPosition;
import java.text.NumberFormat;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.GregorianCalendar;
import javax.swing.JComponent;
import plotter.DateNumberFormat;
import plotter.xy.DefaultXYLayoutGenerator;
import plotter.xy.LinearXYAxis;
import plotter.xy.XYAxis;
import plotter.xy.XYDimension;
import plotter.xy.XYGrid;
import plotter.xy.XYPlot;
import plotter.xy.XYPlotContents;
/**
* Manages the Quinn Curtis objects that come together to form a plot. The axis, the background rectangle etc.
*/
public class QCPlotObjects {
PlotterPlot plot;
private String timeSystemId;
public QCPlotObjects(PlotterPlot thePlot) {
plot = thePlot;
createPlotInstance();
}
void createPlotInstance() {
assert plot.getPlotView()==null: "Plot already initalized.";
// Create new instance of the plot
plot.setPlotView(new XYPlot());
plot.getPlotView().setBackground(PlotConstants.DEFAULT_PLOT_FRAME_BACKGROUND_COLOR);
XYPlotContents contents = new XYPlotContents();
contents.setBackground(Color.black);
plot.getPlotView().add(contents);
plot.getPlotView().setPreferredSize(new Dimension(PlotterPlot.PLOT_PREFERED_WIDTH, PlotterPlot.PLOT_PREFERED_HEIGHT));
// JComponent panel = plot.getPlotPanel();
// GridBagLayout layout = new GridBagLayout();
// panel.setLayout(layout);
// GridBagConstraints constraints = new GridBagConstraints();
// constraints.fill = GridBagConstraints.BOTH;
// constraints.weightx = 1;
// constraints.weighty = 1;
// constraints.gridy = 1;
// constraints.gridwidth = 2;
// layout.setConstraints(plot.getPlotView(), constraints);
// panel.add(plot.getPlotView());
// Setup the plot.
// Note: the order of these operations is important as there are dependencies between plot components.
// Assertion have been added to detect disturbances in the order if the code is changed.
// However, care should be taken when editing this code.
// Setup the time coordinate base of the plot.
setupTimeCoordinates();
// Setup the x- and y-axis.
setupAxis();
setupScrollFrame();
new DefaultXYLayoutGenerator().generateLayout(plot.getPlotView());
}
/**
* Set up the time coordinates according to the plot settings. This is the feature
* that determines axis location and maximum/minimum value locations.
*/
private void setupTimeCoordinates() {
// Set the start/end time boundaries as specified.
plot.setStartTime(new GregorianCalendar());
plot.getStartTime().setTimeInMillis(plot.getMinTime());
plot.setEndTime(new GregorianCalendar());
plot.getEndTime().setTimeInMillis(plot.getMaxTime());
assert(plot.getStartTime()!=null): "Start time should have been initalized by this point.";
assert(plot.getEndTime() != null): "End time should not have been intialized by this point";
}
private NumberFormat getNumberFormatter() {
return PlotConstants.NON_TIME_FORMAT;
}
private void setupAxis() {
assert plot.getPlotView() !=null : "Plot Object not initalized";
if (plot.getAxisOrientationSetting() == AxisOrientationSetting.X_AXIS_AS_TIME) {
// time is on the x-axis.
// Setup the axis.
TimeXYAxis xAxis = new TimeXYAxis(XYDimension.X);
plot.setTimeAxis(xAxis);
if(plot.getXAxisMaximumLocation() == XAxisMaximumLocationSetting.MAXIMUM_AT_RIGHT) {
xAxis.setStart(plot.getStartTime().getTimeInMillis());
xAxis.setEnd(plot.getEndTime().getTimeInMillis());
} else {
xAxis.setStart(plot.getEndTime().getTimeInMillis());
xAxis.setEnd(plot.getStartTime().getTimeInMillis());
}
LinearXYAxis yAxis = new LinearXYAxis(XYDimension.Y);
plot.theNonTimeAxis = yAxis;
if(plot.getYAxisMaximumLocation() == YAxisMaximumLocationSetting.MAXIMUM_AT_TOP) {
yAxis.setStart(plot.getPlotAbstraction().getMinNonTime());
yAxis.setEnd(plot.getPlotAbstraction().getMaxNonTime());
} else {
yAxis.setStart(plot.getPlotAbstraction().getMaxNonTime());
yAxis.setEnd(plot.getPlotAbstraction().getMinNonTime());
}
if(plot.isTimeLabelEnabled) {
xAxis.setPreferredSize(new Dimension(1, 20));
} else {
xAxis.setPreferredSize(new Dimension(1, 10));
}
yAxis.setPreferredSize(new Dimension(PlotConstants.Y_AXIS_WHEN_NON_TIME_LABEL_WIDTH , 1));
xAxis.setForeground(plot.getTimeAxisColor());
yAxis.setForeground(plot.getNonTimeAxisColor());
yAxis.setFormat(getNumberFormatter());
plot.getPlotView().setXAxis(xAxis);
plot.getPlotView().setYAxis(yAxis);
plot.getPlotView().add(xAxis);
plot.getPlotView().add(yAxis);
// Setup the axis labels.
if (plot.isTimeLabelEnabled) {
SimpleDateFormat format = TimeFormatUtils.makeDataFormat(plot.getTimeFormatSetting());
xAxis.setFormat(new DateNumberFormat(format));
xAxis.setTimeSystemAxisLabelName(timeSystemId);
} else {
xAxis.setShowLabels(false);
}
xAxis.setFont(plot.getTimeAxisFont());
yAxis.setFont(plot.getTimeAxisFont());
// Setup the gridlines
XYGrid grid = new XYGrid(xAxis, yAxis);
grid.setForeground(plot.getGridLineColor());
plot.getPlotView().getContents().add(grid);
xAxis.setMinorTickLength(PlotConstants.MINOR_TICK_MARK_LENGTH);
xAxis.setMajorTickLength(PlotConstants.MAJOR_TICK_MARK_LENGTH);
xAxis.setTextMargin(PlotConstants.MAJOR_TICK_MARK_LENGTH + 2);
yAxis.setMinorTickLength(PlotConstants.MINOR_TICK_MARK_LENGTH);
yAxis.setMajorTickLength(PlotConstants.MAJOR_TICK_MARK_LENGTH);
yAxis.setTextMargin(PlotConstants.MAJOR_TICK_MARK_LENGTH + 5);
} else {
assert (plot.getAxisOrientationSetting() == AxisOrientationSetting.Y_AXIS_AS_TIME);
// Setup the axis.
TimeXYAxis yAxis = new TimeXYAxis(XYDimension.Y);
if(plot.getYAxisMaximumLocation() == YAxisMaximumLocationSetting.MAXIMUM_AT_TOP) {
yAxis.setStart(plot.getStartTime().getTimeInMillis());
yAxis.setEnd(plot.getEndTime().getTimeInMillis());
} else {
yAxis.setStart(plot.getEndTime().getTimeInMillis());
yAxis.setEnd(plot.getStartTime().getTimeInMillis());
}
plot.setTimeAxis(yAxis);
LinearXYAxis xAxis = new LinearXYAxis(XYDimension.X);
if(plot.getXAxisMaximumLocation() == XAxisMaximumLocationSetting.MAXIMUM_AT_RIGHT) {
xAxis.setStart(plot.getPlotAbstraction().getMinNonTime());
xAxis.setEnd(plot.getPlotAbstraction().getMaxNonTime());
} else {
xAxis.setStart(plot.getPlotAbstraction().getMaxNonTime());
xAxis.setEnd(plot.getPlotAbstraction().getMinNonTime());
}
plot.theNonTimeAxis = xAxis;
xAxis.setForeground(plot.getNonTimeAxisColor());
yAxis.setForeground(plot.getTimeAxisColor());
xAxis.setFormat(getNumberFormatter());
xAxis.setPreferredSize(new Dimension(1, 20));
yAxis.setPreferredSize(new Dimension(60, 1));
plot.getPlotView().setXAxis(xAxis);
plot.getPlotView().setYAxis(yAxis);
plot.getPlotView().add(xAxis);
plot.getPlotView().add(yAxis);
// Setup the axis labels.
if (plot.isTimeLabelEnabled) {
SimpleDateFormat format = TimeFormatUtils.makeDataFormat(plot.getTimeFormatSetting());
yAxis.setFormat(new DateNumberFormat(format));
yAxis.setTimeSystemAxisLabelName(timeSystemId);
} else {
yAxis.setShowLabels(false);
}
xAxis.setFont(plot.getTimeAxisFont());
yAxis.setFont(plot.getTimeAxisFont());
// Setup the gridlines
XYGrid grid = new XYGrid(xAxis, yAxis);
grid.setForeground(plot.getGridLineColor());
plot.getPlotView().getContents().add(grid);
xAxis.setMajorTickLength(PlotConstants.MAJOR_TICK_MARK_LENGTH);
xAxis.setMinorTickLength(PlotConstants.MINOR_TICK_MARK_LENGTH);
xAxis.setTextMargin(PlotConstants.MAJOR_TICK_MARK_LENGTH + 2);
yAxis.setMajorTickLength(PlotConstants.MAJOR_TICK_MARK_LENGTH);
yAxis.setMinorTickLength(PlotConstants.MINOR_TICK_MARK_LENGTH);
yAxis.setTextMargin(PlotConstants.MAJOR_TICK_MARK_LENGTH + 5);
}
}
void setupScrollFrame() {
assert plot.getPlotView() !=null : "Plot Object not initalized";
TimeAxisSubsequentBoundsSetting mode2 = plot.getTimeAxisSubsequentSetting();
plot.timeScrollModeByPlotSettings = mode2;
plot.setTimeAxisSubsequentSetting(mode2);
// set the Y (non time) scroll mode.
boolean nonTimeMinFixed = plot.getNonTimeAxisSubsequentMinSetting() != NonTimeAxisSubsequentBoundsSetting.AUTO;
boolean nonTimeMaxFixed = plot.getNonTimeAxisSubsequentMaxSetting() != NonTimeAxisSubsequentBoundsSetting.AUTO;;
plot.setNonTimeMinFixedByPlotSettings(nonTimeMinFixed);
plot.setNonTimeMaxFixedByPlotSettings(nonTimeMaxFixed);
plot.setNonTimeMinFixed(nonTimeMinFixed);
plot.setNonTimeMaxFixed(nonTimeMaxFixed);
// Initialization now complete.
}
/**
* Adjusts the span of the plot to match that specified at plot creation time but does not
* fast forward to current time like the companion method @see fastForwardTimeAxisToCurrentMCTTime.
*
* Logic is dependent upon the plot's time axis subsequent bounds setting.
* <ul>
* <li>Jump - sets the upper time to the time plot's current max time. Sets the lower time
* to the current plots max time minus the desired span</li>
* <li>Scrunch - by definition covers from plot inception to the current mct time. It will therefore
* set upper time to the current MCT time and the lower bound to the plot's original lower bound time.</li>
* <li>Fixed - sets the upper time to the time plot's current max time. Sets the lower time
* to the current plots max time minus the desired span</li>
* </ul>
*
*/
void adjustSpanToDesiredSpanWithoutFastFarwardingToCurrentTime() {
long desiredSpan = -1;
long requestMaxTime = -1;
long requestMinTime = -1;
desiredSpan = plot.getMaxTime() - plot.getMinTime();
assert desiredSpan > 0 : "Miscaclulated desired span to be " + desiredSpan;
if (plot.getTimeAxisSubsequentSetting() == TimeAxisSubsequentBoundsSetting.JUMP) {
requestMaxTime = plot.getTimeAxis().getStartAsLong();
requestMinTime = requestMaxTime - desiredSpan;
} else if (plot.getTimeAxisSubsequentSetting() == TimeAxisSubsequentBoundsSetting.SCRUNCH) {
requestMinTime = plot.getMinTime();
requestMaxTime = plot.getPlotAbstraction().getCurrentMCTTime();
} else {
assert false : "other modes not supported";
}
applyMinMaxTimesToPlot(requestMinTime, requestMaxTime);
}
/**
* Sets the time scale start and stop of the plot to the requested min and max time. Method handles axis inversion.
* @param requestMinTime
* @param requestMaxTime
*/
private void applyMinMaxTimesToPlot(long requestMinTime, long requestMaxTime) {
boolean normal = (plot.getAxisOrientationSetting() == AxisOrientationSetting.X_AXIS_AS_TIME) ?
plot.getXAxisMaximumLocation() == XAxisMaximumLocationSetting.MAXIMUM_AT_RIGHT :
plot.getYAxisMaximumLocation() == YAxisMaximumLocationSetting.MAXIMUM_AT_TOP;
assert requestMaxTime != requestMinTime;
AbstractAxis axis = plot.getTimeAxis();
if(normal) {
axis.setStart(requestMinTime);
axis.setEnd(requestMaxTime);
} else {
axis.setEnd(requestMinTime);
axis.setStart(requestMaxTime);
}
}
}