Java tutorial
/* * Debrief - the Open Source Maritime Analysis Application * http://debrief.info * * (C) 2000-2014, PlanetMayo Ltd * * This library is free software; you can redistribute it and/or * modify it under the terms of the Eclipse Public License v1.0 * (http://www.eclipse.org/legal/epl-v10.html) * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ package com.planetmayo.debrief.satc_rcp.views; import java.awt.BasicStroke; import java.awt.Font; import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.ClipboardOwner; import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.Transferable; import java.awt.geom.Point2D; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.text.DecimalFormat; import java.text.NumberFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.TimeZone; import org.eclipse.core.databinding.Binding; import org.eclipse.core.databinding.DataBindingContext; import org.eclipse.core.databinding.beans.BeansObservables; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.databinding.swt.WidgetProperties; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.ComboViewer; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.SashForm; import org.eclipse.swt.custom.ScrolledComposite; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.TabFolder; import org.eclipse.swt.widgets.TabItem; import org.eclipse.ui.IActionBars; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.part.ViewPart; import org.jfree.chart.ChartFactory; import org.jfree.chart.JFreeChart; import org.jfree.chart.annotations.XYTextAnnotation; import org.jfree.chart.axis.DateAxis; import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.event.ChartProgressEvent; import org.jfree.chart.event.ChartProgressListener; import org.jfree.chart.plot.IntervalMarker; import org.jfree.chart.plot.Marker; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; import org.jfree.data.time.FixedMillisecond; import org.jfree.data.time.TimeSeries; import org.jfree.data.time.TimeSeriesCollection; import org.jfree.experimental.chart.swt.ChartComposite; import org.jfree.ui.Layer; import org.jfree.ui.RectangleAnchor; import org.jfree.ui.TextAnchor; import org.jfree.util.ShapeUtilities; import org.swtchart.Chart; import org.swtchart.IAxis; import org.swtchart.IBarSeries; import org.swtchart.ISeries; import org.swtchart.ISeries.SeriesType; import com.planetmayo.debrief.satc.log.LogFactory; import com.planetmayo.debrief.satc.model.Precision; import com.planetmayo.debrief.satc.model.VehicleType; import com.planetmayo.debrief.satc.model.contributions.ATBForecastContribution; import com.planetmayo.debrief.satc.model.contributions.BaseContribution; import com.planetmayo.debrief.satc.model.contributions.BearingMeasurementContribution; import com.planetmayo.debrief.satc.model.contributions.BearingMeasurementContribution.BMeasurement; import com.planetmayo.debrief.satc.model.contributions.BearingMeasurementContribution.HostState; import com.planetmayo.debrief.satc.model.contributions.BearingMeasurementContribution.MDAResultsListener; import com.planetmayo.debrief.satc.model.contributions.CompositeStraightLegForecastContribution; import com.planetmayo.debrief.satc.model.contributions.ContributionBuilder; import com.planetmayo.debrief.satc.model.contributions.CourseForecastContribution; import com.planetmayo.debrief.satc.model.contributions.FrequencyMeasurementContribution; import com.planetmayo.debrief.satc.model.contributions.LocationForecastContribution; import com.planetmayo.debrief.satc.model.contributions.Range1959ForecastContribution; import com.planetmayo.debrief.satc.model.contributions.RangeForecastContribution; import com.planetmayo.debrief.satc.model.contributions.SpeedForecastContribution; import com.planetmayo.debrief.satc.model.contributions.StraightLegForecastContribution; import com.planetmayo.debrief.satc.model.generator.IBoundsManager; import com.planetmayo.debrief.satc.model.generator.IConstrainSpaceListener; import com.planetmayo.debrief.satc.model.generator.IContributions; import com.planetmayo.debrief.satc.model.generator.IContributionsChangedListener; import com.planetmayo.debrief.satc.model.generator.ISolver; import com.planetmayo.debrief.satc.model.generator.SteppingAdapter; import com.planetmayo.debrief.satc.model.generator.impl.ga.IGASolutionsListener; import com.planetmayo.debrief.satc.model.legs.CompositeRoute; import com.planetmayo.debrief.satc.model.legs.CoreRoute; import com.planetmayo.debrief.satc.model.manager.IContributionsManager; import com.planetmayo.debrief.satc.model.manager.ISolversManager; import com.planetmayo.debrief.satc.model.manager.ISolversManagerListener; import com.planetmayo.debrief.satc.model.manager.IVehicleTypesManager; import com.planetmayo.debrief.satc.model.states.BaseRange.IncompatibleStateException; import com.planetmayo.debrief.satc.model.states.State; import com.planetmayo.debrief.satc.util.GeoSupport; import com.planetmayo.debrief.satc.util.calculator.GeodeticCalculator; import com.planetmayo.debrief.satc.zigdetector.LegOfData; import com.planetmayo.debrief.satc_rcp.SATC_Activator; import com.planetmayo.debrief.satc_rcp.ui.UIListener; import com.planetmayo.debrief.satc_rcp.ui.UIUtils; import com.planetmayo.debrief.satc_rcp.ui.contributions.ATBForecastContributionView; import com.planetmayo.debrief.satc_rcp.ui.contributions.BaseContributionView; import com.planetmayo.debrief.satc_rcp.ui.contributions.BearingMeasurementContributionView; import com.planetmayo.debrief.satc_rcp.ui.contributions.CompositeStraightLegForecastContributionView; import com.planetmayo.debrief.satc_rcp.ui.contributions.CourseContributionView; import com.planetmayo.debrief.satc_rcp.ui.contributions.FrequencyMeasurementContributionView; import com.planetmayo.debrief.satc_rcp.ui.contributions.LocationForecastContributionView; import com.planetmayo.debrief.satc_rcp.ui.contributions.RangeForecastContributionView; import com.planetmayo.debrief.satc_rcp.ui.contributions.Ranging1959ContributionView; import com.planetmayo.debrief.satc_rcp.ui.contributions.SpeedContributionView; import com.planetmayo.debrief.satc_rcp.ui.contributions.StraightLegForecastContributionView; /** * mock class to test high level application flows * * @author ian * */ public class MaintainContributionsView extends ViewPart { private static final String PERFORMANCE_TITLE = "Overall score:"; private static final String TITLE = "Maintain Contributions"; private static final Map<Class<? extends BaseContribution>, Class<? extends BaseContributionView<?>>> CONTRIBUTION_PANELS; static { CONTRIBUTION_PANELS = new HashMap<Class<? extends BaseContribution>, Class<? extends BaseContributionView<?>>>(); CONTRIBUTION_PANELS.put(ATBForecastContribution.class, ATBForecastContributionView.class); CONTRIBUTION_PANELS.put(BearingMeasurementContribution.class, BearingMeasurementContributionView.class); CONTRIBUTION_PANELS.put(FrequencyMeasurementContribution.class, FrequencyMeasurementContributionView.class); CONTRIBUTION_PANELS.put(CourseForecastContribution.class, CourseContributionView.class); CONTRIBUTION_PANELS.put(LocationForecastContribution.class, LocationForecastContributionView.class); CONTRIBUTION_PANELS.put(Range1959ForecastContribution.class, Ranging1959ContributionView.class); CONTRIBUTION_PANELS.put(RangeForecastContribution.class, RangeForecastContributionView.class); CONTRIBUTION_PANELS.put(SpeedForecastContribution.class, SpeedContributionView.class); CONTRIBUTION_PANELS.put(CompositeStraightLegForecastContribution.class, CompositeStraightLegForecastContributionView.class); CONTRIBUTION_PANELS.put(StraightLegForecastContribution.class, StraightLegForecastContributionView.class); } /** UI fields */ private DataBindingContext context; private Composite main; private Button liveConstraints; private Button recalculate; private Button cancelGeneration; private Button suppressCuts; private Button showOSCourse; private ComboViewer precisionsCombo; // private ComboViewer vehiclesCombo; private Composite contList; // private Menu addContributionMenu; // private ToolItem addContributionButton; private transient HashMap<BaseContribution, Color> assignedColors; /** Contribution -> Contribution view mappings */ private HashMap<BaseContribution, BaseContributionView<?>> contributionsControl = new HashMap<BaseContribution, BaseContributionView<?>>(); private ISolver activeSolver; private ISolversManager solversManager; /** * current listeners */ private Binding liveRunningBinding; private IContributionsChangedListener contributionsChangedListener; private IGASolutionsListener generateSolutionsListener; private ISolversManagerListener solverManagerListener; private IConstrainSpaceListener constrainSpaceListener; private Chart performanceChart; private final java.awt.Color[] defaultColors = new java.awt.Color[] { java.awt.Color.red, java.awt.Color.green, java.awt.Color.yellow, java.awt.Color.blue, java.awt.Color.cyan, java.awt.Color.magenta, java.awt.Color.darkGray, java.awt.Color.orange, java.awt.Color.pink, java.awt.Color.lightGray }; private XYPlot legPlot; private Composite legGraphComposite; private PropertyChangeListener _legListener; private TabItem performanceTab; private TabItem legTab; private TabFolder graphTabs; private MDAResultsListener _sliceListener; private JFreeChart legChart; private Action _exportBtn; private Color _colorBlack; @Override public void createPartControl(final Composite parent) { context = new DataBindingContext(); IContributionsManager contributionsManager = SATC_Activator.getDefault() .getService(IContributionsManager.class, true); IVehicleTypesManager vehicleManager = SATC_Activator.getDefault().getService(IVehicleTypesManager.class, true); solversManager = SATC_Activator.getDefault().getService(ISolversManager.class, true); initUI(parent); populateContributionList(contributionsManager.getAvailableContributions()); populatePrecisionsList(Precision.values()); populateVehicleTypesList(vehicleManager.getAllTypes()); initListeners(parent); solversManager.addSolversManagerListener(solverManagerListener); // also, set the help context PlatformUI.getWorkbench().getHelpSystem().setHelp(parent, "org.mwc.debrief.help.SATC"); setActiveSolver(solversManager.getActiveSolver()); } @Override public void dispose() { context.dispose(); setActiveSolver(null); solversManager.removeSolverManagerListener(solverManagerListener); // ditch the colors if (assignedColors != null) { Iterator<Color> cIter = assignedColors.values().iterator(); while (cIter.hasNext()) { org.eclipse.swt.graphics.Color entry = cIter.next(); entry.dispose(); } assignedColors = null; } // and our SWT black shade if (!_colorBlack.isDisposed()) _colorBlack.dispose(); super.dispose(); } @Override public void setFocus() { } private void fillAnalystContributionsGroup(Composite parent) { GridLayout layout = new GridLayout(4, false); layout.marginHeight = 2; layout.marginWidth = 2; Composite header = UIUtils.createEmptyComposite(parent, layout, new GridData(GridData.FILL_HORIZONTAL)); UIUtils.createSpacer(header, new GridData(50, SWT.DEFAULT)); Composite headerNested = UIUtils.createEmptyComposite(header, UIUtils.createGridLayoutWithoutMargins(4, true), new GridData(GridData.FILL_HORIZONTAL)); UIUtils.createLabel(headerNested, SWT.CENTER, "Active", new GridData(GridData.FILL_HORIZONTAL)); UIUtils.createLabel(headerNested, SWT.CENTER, "Hard constraints", new GridData(GridData.FILL_HORIZONTAL)); UIUtils.createLabel(headerNested, SWT.CENTER, "Estimate", new GridData(GridData.FILL_HORIZONTAL)); UIUtils.createLabel(headerNested, SWT.CENTER, "Weighting", new GridData(GridData.HORIZONTAL_ALIGN_END)); UIUtils.createLabel(header, SWT.CENTER, "Delete", new GridData(GridData.HORIZONTAL_ALIGN_END)); UIUtils.createSpacer(header, new GridData(20, SWT.DEFAULT)); } private void initAddContributionGroup(Composite parent) { // GridData gridData = new GridData(); // gridData.horizontalAlignment = SWT.FILL; // gridData.grabExcessHorizontalSpace = true; // // Group group = new Group(parent, SWT.SHADOW_ETCHED_IN); // FillLayout fillLayout = new FillLayout(); // fillLayout.marginWidth = 5; // fillLayout.marginHeight = 5; // group.setLayout(fillLayout); // group.setLayoutData(gridData); // group.setText("New Contribution"); // // addContributionMenu = new Menu(group); // final ToolBar toolBar = new ToolBar(group, SWT.NONE); // toolBar.setBounds(50, 50, 50, 50); // addContributionButton = new ToolItem(toolBar, SWT.DROP_DOWN); // addContributionButton.setText("Add..."); // addContributionButton.addListener(SWT.Selection, new Listener() // { // @Override // public void handleEvent(Event event) // { // if (event.detail == SWT.ARROW) // { // Rectangle rect = addContributionButton.getBounds(); // Point pt = new Point(rect.x, rect.y + rect.height); // pt = toolBar.toDisplay(pt); // addContributionMenu.setLocation(pt.x, pt.y); // addContributionMenu.setVisible(true); // } // } // }); } private void initAnalystContributionsGroup(Composite parent) { GridData gridData = new GridData(); gridData.horizontalAlignment = SWT.FILL; gridData.verticalAlignment = SWT.FILL; gridData.grabExcessHorizontalSpace = true; gridData.grabExcessVerticalSpace = true; Group group = new Group(parent, SWT.SHADOW_ETCHED_IN); group.setLayout(new GridLayout(1, false)); group.setLayoutData(gridData); group.setText("Analyst Contributions"); fillAnalystContributionsGroup(group); final ScrolledComposite scrolled = new ScrolledComposite(group, SWT.V_SCROLL | SWT.H_SCROLL); scrolled.setLayoutData(new GridData(GridData.FILL_BOTH)); contList = UIUtils.createScrolledBody(scrolled, SWT.NONE); contList.setLayout(new GridLayout(1, false)); scrolled.addListener(SWT.Resize, new Listener() { @Override public void handleEvent(Event e) { scrolled.setMinSize(contList.computeSize(SWT.DEFAULT, SWT.DEFAULT)); } }); scrolled.setAlwaysShowScrollBars(true); scrolled.setContent(contList); scrolled.setMinSize(contList.computeSize(SWT.DEFAULT, SWT.DEFAULT)); scrolled.setExpandHorizontal(true); scrolled.setExpandVertical(true); } private void initPreferencesGroup(Composite parent) { GridData gridData = new GridData(); gridData.horizontalAlignment = SWT.FILL; gridData.grabExcessHorizontalSpace = true; Group group = new Group(parent, SWT.SHADOW_ETCHED_IN); GridLayout layout = new GridLayout(1, false); group.setLayoutData(gridData); group.setLayout(layout); group.setText("Preferences"); final ScrolledComposite scrolled = new ScrolledComposite(group, SWT.H_SCROLL); scrolled.setLayoutData(new GridData(GridData.FILL_BOTH)); final Composite preferencesComposite = UIUtils.createScrolledBody(scrolled, SWT.NONE); preferencesComposite.setLayout(new GridLayout(6, false)); scrolled.addListener(SWT.Resize, new Listener() { @Override public void handleEvent(Event e) { scrolled.setMinSize(preferencesComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT)); } }); scrolled.setAlwaysShowScrollBars(true); scrolled.setContent(preferencesComposite); scrolled.setMinSize(preferencesComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT)); scrolled.setExpandHorizontal(true); scrolled.setExpandVertical(true); liveConstraints = new Button(preferencesComposite, SWT.TOGGLE); liveConstraints.setText("Auto-Recalc of Constraints"); liveConstraints.setEnabled(false); liveConstraints .setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING | GridData.VERTICAL_ALIGN_CENTER)); recalculate = new Button(preferencesComposite, SWT.DEFAULT); recalculate.setText("Calculate Solution"); recalculate.setEnabled(false); recalculate.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { if (activeSolver != null) { // ok - make sure the performance tab is open graphTabs.setSelection(performanceTab); activeSolver.run(true, true); main.setSize(0, 0); main.getParent().layout(true, true); } } }); recalculate.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_CENTER | GridData.VERTICAL_ALIGN_CENTER)); cancelGeneration = new Button(preferencesComposite, SWT.PUSH); cancelGeneration.setText("Cancel"); cancelGeneration.setVisible(false); cancelGeneration.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { if (activeSolver != null) { activeSolver.cancel(); } } }); suppressCuts = new Button(preferencesComposite, SWT.CHECK); suppressCuts.setText("Suppress Cuts"); suppressCuts.setVisible(true); suppressCuts.setEnabled(false); suppressCuts.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { if (activeSolver != null) { boolean doSuppress = suppressCuts.getSelection(); activeSolver.setAutoSuppress(doSuppress); } } }); showOSCourse = new Button(preferencesComposite, SWT.CHECK); showOSCourse.setText("Plot O/S Course"); showOSCourse.setVisible(true); showOSCourse.setEnabled(false); showOSCourse.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { if (activeSolver != null) { redoOwnshipStates(); } } }); Composite precisionPanel = new Composite(preferencesComposite, SWT.NONE); precisionPanel.setLayoutData(new GridData( GridData.HORIZONTAL_ALIGN_END | GridData.GRAB_HORIZONTAL | GridData.VERTICAL_ALIGN_CENTER)); GridLayout precisionLayout = new GridLayout(2, false); precisionLayout.horizontalSpacing = 5; precisionPanel.setLayout(precisionLayout); Label precisionLabel = new Label(precisionPanel, SWT.NONE); precisionLabel.setText("Precision:"); precisionLabel.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_CENTER)); precisionsCombo = new ComboViewer(precisionPanel); precisionsCombo.getCombo().setEnabled(false); precisionsCombo.setContentProvider(new ArrayContentProvider()); precisionsCombo.setLabelProvider(new LabelProvider() { @Override public String getText(Object element) { return ((Precision) element).getLabel(); } }); precisionsCombo.addSelectionChangedListener(new ISelectionChangedListener() { @Override public void selectionChanged(SelectionChangedEvent event) { ISelection sel = precisionsCombo.getSelection(); IStructuredSelection cSel = (IStructuredSelection) sel; Precision precision = (Precision) cSel.getFirstElement(); if (activeSolver != null) { activeSolver.setPrecision(precision); } } }); } private void initUI(final Composite parent) { parent.setLayout(new FillLayout()); final SashForm sashForm = new SashForm(parent, SWT.VERTICAL); sashForm.SASH_WIDTH = 15; sashForm.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_GRAY)); main = new Composite(sashForm, SWT.NONE); GridLayout gridLayout = new GridLayout(1, true); gridLayout.verticalSpacing = 2; gridLayout.marginLeft = 5; gridLayout.marginRight = 5; main.setLayout(gridLayout); initPreferencesGroup(main); initVehicleGroup(main); initAnalystContributionsGroup(main); initAddContributionGroup(main); Composite lowerSection = new Composite(sashForm, SWT.NONE); lowerSection.setLayout(new FillLayout()); // ok - the next section needs to be in a sash - so we can resize it initGraphTabs(lowerSection); // set the relative sizes in the sash sashForm.setWeights(new int[] { 3, 1 }); // also sort out the header controls final IActionBars bars = getViewSite().getActionBars(); IToolBarManager manager = bars.getToolBarManager(); manager.add(SATC_Activator.createOpenHelpAction("org.mwc.debrief.help.SATC", null, this)); _exportBtn = new Action("Export SATC dataset", Action.AS_PUSH_BUTTON) { public void runWithEvent(final Event event) { exportSATC(); } }; _exportBtn.setToolTipText("Export SATC scenario to clipboard"); _exportBtn.setImageDescriptor(SATC_Activator.getImageDescriptor("icons/export.png")); manager.add(_exportBtn); } private void initGraphTabs(Composite parent) { GridData gridData = new GridData(); gridData.horizontalAlignment = SWT.FILL; gridData.grabExcessHorizontalSpace = true; gridData.heightHint = 200; graphTabs = new TabFolder(parent, SWT.BORDER); FillLayout fillLayout = new FillLayout(); fillLayout.marginWidth = 5; fillLayout.marginHeight = 5; // tabs.setLayout(fillLayout); graphTabs.setLayoutData(gridData); legTab = new TabItem(graphTabs, SWT.NONE); legTab.setText("Ownship && Target Legs"); legGraphComposite = initLegGraph(graphTabs); legTab.setControl(legGraphComposite); performanceTab = new TabItem(graphTabs, SWT.NONE); performanceTab.setText("Performance"); Group perfG2 = initPerformanceGraph(graphTabs); performanceTab.setControl(perfG2); } private Group initPerformanceGraph(Composite parent) { GridData gridData = new GridData(); gridData.horizontalAlignment = SWT.FILL; gridData.grabExcessHorizontalSpace = true; gridData.heightHint = 200; Group group = new Group(parent, SWT.SHADOW_ETCHED_IN); FillLayout fillLayout = new FillLayout(); fillLayout.marginWidth = 5; fillLayout.marginHeight = 5; group.setLayout(fillLayout); group.setLayoutData(gridData); // group.setText("Performance"); // we need the color black several times _colorBlack = new Color(Display.getCurrent(), 0, 0, 0); // generate the chart performanceChart = new Chart(group, SWT.NONE); // format the chart performanceChart.getLegend().setVisible(false); performanceChart.getTitle().setVisible(true); performanceChart.setForeground(_colorBlack); performanceChart.getTitle().setText(PERFORMANCE_TITLE + " Pending"); performanceChart.getTitle().setForeground(_colorBlack); // now give the chart our data series // ok, now for the x axis IAxis xAxis = performanceChart.getAxisSet().getXAxis(0); xAxis.getTitle().setVisible(false); xAxis.adjustRange(); xAxis.getTick().setForeground(_colorBlack); // and the y axis IAxis yAxis = performanceChart.getAxisSet().getYAxis(0); yAxis.adjustRange(); yAxis.enableLogScale(true); yAxis.getTick().setForeground(_colorBlack); yAxis.getTitle().setForeground(_colorBlack); yAxis.getTitle().setText("Weighted error"); return group; } /** * This is a callback that will allow us to create the viewer and initialize * it. */ public Composite initLegGraph(final Composite parent) { legChart = ChartFactory.createTimeSeriesChart("Ownship & Target Legs", // String "Time", // String timeAxisLabel null, // String valueAxisLabel, null, // XYDataset dataset, true, // include legend true, // tooltips false); // urls legPlot = (XYPlot) legChart.getPlot(); legPlot.setDomainCrosshairVisible(true); legPlot.setRangeCrosshairVisible(true); final DateAxis axis = (DateAxis) legPlot.getDomainAxis(); axis.setDateFormatOverride(new SimpleDateFormat("HH:mm:ss")); legPlot.setBackgroundPaint(java.awt.Color.WHITE); legPlot.setRangeGridlinePaint(java.awt.Color.LIGHT_GRAY); legPlot.setDomainGridlinePaint(java.awt.Color.LIGHT_GRAY); // format the cross hairs, when they're clicked legPlot.setDomainCrosshairVisible(true); legPlot.setRangeCrosshairVisible(true); legPlot.setDomainCrosshairPaint(java.awt.Color.GRAY); legPlot.setRangeCrosshairPaint(java.awt.Color.GRAY); legPlot.setDomainCrosshairStroke(new BasicStroke(1)); legPlot.setRangeCrosshairStroke(new BasicStroke(1)); // and the plot object to display the cross hair value final XYTextAnnotation annot = new XYTextAnnotation("-----", 0, 0); annot.setTextAnchor(TextAnchor.TOP_LEFT); annot.setPaint(java.awt.Color.black); annot.setBackgroundPaint(java.awt.Color.white); legPlot.addAnnotation(annot); legChart.addProgressListener(new ChartProgressListener() { public void chartProgress(final ChartProgressEvent cpe) { if (cpe.getType() != ChartProgressEvent.DRAWING_FINISHED) return; // double-check our label is still in the right place final double xVal = legPlot.getRangeAxis().getUpperBound(); final double yVal = legPlot.getDomainAxis().getLowerBound(); boolean annotChanged = false; if (annot.getX() != yVal) { annot.setX(yVal); annotChanged = true; } if (annot.getY() != xVal) { annot.setY(xVal); annotChanged = true; } // and write the text final NumberFormat _oneDPFormat = new DecimalFormat("0.0", new java.text.DecimalFormatSymbols(java.util.Locale.UK)); final String numA = _oneDPFormat.format(legPlot.getRangeCrosshairValue()); final Date newDate = new Date((long) legPlot.getDomainCrosshairValue()); final SimpleDateFormat _df = new SimpleDateFormat("HHmm:ss"); _df.setTimeZone(TimeZone.getTimeZone("GMT")); final String dateVal = _df.format(newDate); final String theMessage = " [" + dateVal + "," + numA + "]"; if (!theMessage.equals(annot.getText())) { annot.setText(theMessage); annotChanged = true; } // aah, now we have to add and then remove the annotation in order // for the new text value to be displayed. Watch and learn... if (annotChanged) { legPlot.removeAnnotation(annot); legPlot.addAnnotation(annot); } } }); ChartComposite chartFrame = new ChartComposite(parent, SWT.NONE, legChart, true) { @Override public void mouseUp(MouseEvent event) { super.mouseUp(event); JFreeChart c = getChart(); if (c != null) { c.setNotify(true); // force redraw } } }; chartFrame.setDisplayToolTips(true); chartFrame.setHorizontalAxisTrace(false); chartFrame.setVerticalAxisTrace(false); return chartFrame; } /** * clear the data on the leg graph * */ private void clearLegGraph() { if (legPlot == null) return; if ((legGraphComposite == null) || (legGraphComposite.isDisposed())) return; legPlot.setDataset(0, null); legPlot.setDataset(1, null); legPlot.setDataset(2, null); legPlot.setDataset(3, null); legPlot.clearDomainMarkers(); } private void clearPerformanceGraph() { // hmm, have we already ditched? if (performanceChart.isDisposed()) return; ISeries[] sets = performanceChart.getSeriesSet().getSeries(); for (int i = 0; i < sets.length; i++) { ISeries iSeries = sets[i]; performanceChart.getSeriesSet().deleteSeries(iSeries.getId()); } // ySeries.setYSeries(newYVals); performanceChart.getAxisSet().getXAxis(0).adjustRange(); performanceChart.getAxisSet().getYAxis(0).adjustRange(); performanceChart.getAxisSet().getYAxis(0).enableLogScale(true); performanceChart.redraw(); } private Color colorFor(BaseContribution contribution) { if (assignedColors == null) { assignedColors = new HashMap<BaseContribution, Color>(); } // have we already assigned this one? Color res = assignedColors.get(contribution); if (res == null) { int index = assignedColors.size() % defaultColors.length; java.awt.Color newCol = defaultColors[index]; res = new Color(Display.getDefault(), newCol.getRed(), newCol.getGreen(), newCol.getBlue()); assignedColors.put(contribution, res); } return res; } private void addNewPerformanceScore(double value, List<CompositeRoute> topRoutes) { // remember each contribution's set of scores HashMap<BaseContribution, HashMap<Date, Double>> stackedSeries = new HashMap<BaseContribution, HashMap<Date, Double>>(); // remember the times for which we have states ArrayList<Date> valueTimes = new ArrayList<Date>(); // ok - have a look at the scores Iterator<CoreRoute> legIter = topRoutes.get(0).getLegs().iterator(); while (legIter.hasNext()) { CoreRoute route = legIter.next(); Iterator<State> states = route.getStates().iterator(); while (states.hasNext()) { State state = states.next(); HashMap<BaseContribution, Double> scores = state.getScores(); Iterator<BaseContribution> contributions = scores.keySet().iterator(); while (contributions.hasNext()) { BaseContribution cont = contributions.next(); // get the score Double score = scores.get(cont); if (score > 0) { HashMap<Date, Double> thisSeries = stackedSeries.get(cont); if (thisSeries == null) { thisSeries = new HashMap<Date, Double>(); stackedSeries.put(cont, thisSeries); final IBarSeries series = (IBarSeries) performanceChart.getSeriesSet() .createSeries(SeriesType.BAR, cont.getName()); series.setBarColor(colorFor(cont)); // series.enableStack(true); } thisSeries.put(state.getTime(), scores.get(cont)); // store the time of this value if (!valueTimes.contains(state.getTime())) { valueTimes.add(state.getTime()); } } } } } // ok, now loop through the series Iterator<BaseContribution> conts = stackedSeries.keySet().iterator(); while (conts.hasNext()) { BaseContribution cont = conts.next(); HashMap<Date, Double> vals = stackedSeries.get(cont); if (vals.size() > 0) { final IBarSeries series = (IBarSeries) performanceChart.getSeriesSet().getSeries(cont.getName()); // ok, we need to produce a value for each value time double[] valArr = new double[valueTimes.size()]; Iterator<Date> iter2 = valueTimes.iterator(); int ctr = 0; while (iter2.hasNext()) { Date date = iter2.next(); Double thisV = vals.get(date); final double res; if (thisV != null) res = thisV; else res = 0; valArr[ctr++] = res; } series.setYSeries(valArr); // series.enableStack(true); } } // prepare the category labels String[] labels = new String[valueTimes.size()]; Iterator<Date> vIter = valueTimes.iterator(); // get our date formatter ready SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); sdf.setTimeZone(TimeZone.getTimeZone("GMT")); // determine frequency f (trim to 1) int wid = performanceChart.getBounds().width; int allowed = wid / 90; int freq = Math.max(labels.length / allowed, 1); int ctr = 0; while (vIter.hasNext()) { Date date = vIter.next(); final String str; if (ctr % freq == 0) str = sdf.format(date); else str = ""; labels[ctr++] = str; } // set category labels performanceChart.getAxisSet().getXAxis(0).enableCategory(true); performanceChart.getAxisSet().getXAxis(0).setCategorySeries(labels); ISeries[] series = performanceChart.getSeriesSet().getSeries(); if (series.length == 2 && series[0] instanceof IBarSeries && series[1] instanceof IBarSeries) { performanceChart.getLegend().setVisible(true); performanceChart.getLegend().setPosition(SWT.RIGHT); IBarSeries barSeries1 = (IBarSeries) series[0]; IBarSeries barSeries2 = (IBarSeries) series[1]; // enable stack series barSeries1.enableStack(false); barSeries2.enableStack(false); barSeries1.enableStack(true); barSeries2.enableStack(true); } // and resize the axes performanceChart.getAxisSet().adjustRange(); final String perfString; if (value > 200d) perfString = "Unachievable"; else perfString = PERFORMANCE_TITLE + (int) value; performanceChart.getTitle().setText(perfString); // performanceChart.redraw(); } private void initVehicleGroup(Composite parent) { // GridData gridData = new GridData(); // gridData.horizontalAlignment = SWT.FILL; // gridData.grabExcessHorizontalSpace = true; // // Group group = new Group(parent, SWT.SHADOW_ETCHED_IN); // FillLayout fillLayout = new FillLayout(); // fillLayout.marginWidth = 5; // fillLayout.marginHeight = 5; // group.setLayout(fillLayout); // group.setLayoutData(gridData); // group.setText("Vehicle"); // // vehiclesCombo = new ComboViewer(group); // vehiclesCombo.setContentProvider(new ArrayContentProvider()); // vehiclesCombo.setLabelProvider(new LabelProvider() // { // // @Override // public String getText(Object element) // { // return ((VehicleType) element).getName(); // } // }); // vehiclesCombo.addSelectionChangedListener(new // ISelectionChangedListener() // { // // @Override // public void selectionChanged(SelectionChangedEvent event) // { // if (activeSolver != null) // { // ISelection selection = event.getSelection(); // if (selection instanceof StructuredSelection) // { // VehicleType type = // (VehicleType) ((StructuredSelection) selection) // .getFirstElement(); // activeSolver.setVehicleType(type); // } // } // } // }); } public void populateContributionList(List<ContributionBuilder> items) { // for (final ContributionBuilder item : items) // { // MenuItem menuItem = new MenuItem(addContributionMenu, SWT.PUSH); // menuItem.setText(item.getDescription()); // menuItem.addSelectionListener(new SelectionAdapter() // { // @Override // public void widgetSelected(SelectionEvent arg0) // { // if (activeSolver != null) // { // activeSolver.getContributions().addContribution(item.create()); // } // } // }); // } } public void populatePrecisionsList(Precision[] precisions) { precisionsCombo.setInput(precisions); precisionsCombo.setSelection(new StructuredSelection(precisions[0])); } public void populateVehicleTypesList(List<VehicleType> vehicles) { // vehiclesCombo.setInput(vehicles); // // // ok, try to set the first one // if (vehicles.size() > 0) // { // vehiclesCombo.setSelection(new // StructuredSelection(vehicles.iterator() // .next())); // } } private void initListeners(final Composite parent) { contributionsChangedListener = UIListener.wrap(parent.getDisplay(), IContributionsChangedListener.class, new IContributionsChangedListener() { @Override public void removed(BaseContribution contribution) { removeContribution(contribution, true); } @Override public void added(BaseContribution contribution) { addContribution(contribution, true); } @Override public void modified() { } }); generateSolutionsListener = UIListener.wrap(parent.getDisplay(), IGASolutionsListener.class, new SteppingAdapter() { Control focused = null; @Override public void startingGeneration() { focused = parent.getDisplay().getFocusControl(); UIUtils.setEnabled(parent, false); cancelGeneration.setVisible(true); cancelGeneration.setEnabled(true); // ok, clear the graph clearPerformanceGraph(); } @Override public void iterationComputed(List<CompositeRoute> topRoutes, double topScore) { addNewPerformanceScore(topScore, topRoutes); } @Override public void finishedGeneration(Throwable error) { UIUtils.setEnabled(parent, true); cancelGeneration.setVisible(false); // we've encountered an instance during file-load where // focused // is // null, better check it if (focused != null) focused.setFocus(); } }); solverManagerListener = UIListener.wrap(parent.getDisplay(), ISolversManagerListener.class, new ISolversManagerListener() { @Override public void solverCreated(final ISolver solver) { } @Override public void activeSolverChanged(final ISolver activeSolver) { setActiveSolver(activeSolver); } }); constrainSpaceListener = UIListener.wrap(parent.getDisplay(), IConstrainSpaceListener.class, new IConstrainSpaceListener() { @Override public void stepped(IBoundsManager boundsManager, int thisStep, int totalSteps) { } @Override public void statesBounded(IBoundsManager boundsManager) { // minimum steps to get the contributions list to redraw contList.setSize(0, 0); } @Override public void restarted(IBoundsManager boundsManager) { } @Override public void error(IBoundsManager boundsManager, IncompatibleStateException ex) { } }); } public void setActiveSolver(final ISolver solver) { // just double check that we aren't already looking at this solver if (solver != activeSolver) { // other UI mgt if (activeSolver != null) { // cancel listeners activeSolver.getContributions().removeContributionsChangedListener(contributionsChangedListener); activeSolver.getSolutionGenerator().removeReadyListener(generateSolutionsListener); activeSolver.getBoundsManager().removeConstrainSpaceListener(constrainSpaceListener); liveRunningBinding.dispose(); } // drop the contributions List<BaseContribution> contributions = new ArrayList<BaseContribution>(contributionsControl.keySet()); for (BaseContribution contribution : contributions) { removeContribution(contribution, false); } if (!contList.isDisposed()) { contList.layout(); } // clear the charts - just in case clearPerformanceGraph(); clearLegGraph(); activeSolver = solver; boolean hasSolver = activeSolver != null; if (hasSolver) { activeSolver.getContributions().addContributionsChangedListener(contributionsChangedListener); activeSolver.getSolutionGenerator().addReadyListener(generateSolutionsListener); activeSolver.getBoundsManager().addConstrainSpaceListener(constrainSpaceListener); for (BaseContribution contribution : activeSolver.getContributions()) { addContribution(contribution, false); } contList.layout(); // vehiclesCombo.setSelection(new // StructuredSelection(activeSolver // .getVehicleType())); precisionsCombo.setSelection(new StructuredSelection(activeSolver.getPrecision())); suppressCuts.setSelection(activeSolver.getAutoSuppress()); liveRunningBinding = context.bindValue(WidgetProperties.selection().observe(liveConstraints), BeansObservables.observeValue(activeSolver, ISolver.LIVE_RUNNING)); setPartName(TITLE + " - " + activeSolver.getName()); } else { setPartName(TITLE); } if (!contList.isDisposed()) { precisionsCombo.getCombo().setEnabled(hasSolver); liveConstraints.setEnabled(hasSolver); recalculate.setEnabled(hasSolver); performanceChart.setEnabled(hasSolver); suppressCuts.setEnabled(hasSolver); showOSCourse.setEnabled(hasSolver); // vehiclesCombo.getCombo().setEnabled(hasSolver); // addContributionButton.setEnabled(hasSolver); } } } public void addContribution(BaseContribution contribution, boolean doLayout) { // ok, create a wrapper for this BaseContributionView<?> panel = null; if (!CONTRIBUTION_PANELS.containsKey(contribution.getClass())) { return; } try { Class<?> viewClass = CONTRIBUTION_PANELS.get(contribution.getClass()); panel = (BaseContributionView<?>) viewClass .getConstructor(Composite.class, contribution.getClass(), IContributions.class) .newInstance(contList, contribution, activeSolver.getContributions()); panel.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL)); // see if we can give it a default color panel.setDefaultColor(colorFor(contribution)); // now store it contributionsControl.put(contribution, panel); if (doLayout) { contList.layout(); } // hmm, is this a new straight leg? if (contribution instanceof StraightLegForecastContribution) { // ok - listen out for period changes StraightLegForecastContribution slf = (StraightLegForecastContribution) contribution; if (_legListener == null) _legListener = new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { redoStraightLegs(); } }; startListeningTo(slf); // ok - chuck in a graph update redoStraightLegs(); } else if (contribution instanceof BearingMeasurementContribution) { BearingMeasurementContribution bmc = (BearingMeasurementContribution) contribution; if (_sliceListener == null) { _sliceListener = new BearingMeasurementContribution.MDAResultsListener() { @Override public void startingSlice(String contName) { // ok - ownship course is important for this - show it showOSCourse.setSelection(true); startSlicingOwnshipLegs(contName); } @Override public void ownshipLegs(String contName, ArrayList<BMeasurement> bearings, List<LegOfData> ownshipLegs, ArrayList<HostState> hostStates) { // clear the domain markers, this is a new dataset legPlot.clearDomainMarkers(); // and show the ownship states redoOwnshipStates(); } @Override public void sliced(String contName, ArrayList<StraightLegForecastContribution> arrayList) { // are we currently showing ownship course? if (showOSCourse.getSelection()) { // ok, ownship course is irrelevant to this, hide it showOSCourse.setSelection(false); // update the ownship states, now that we've hidden the O/S course redoOwnshipStates(); } // ok, now display the target legs redoStraightLegs(); } }; } bmc.addSliceListener(_sliceListener); // hey, let's also re-display the ownship states redoOwnshipStates(); } } catch (Exception ex) { LogFactory.getLog().error("Failed to generate panel for " + contribution); SATC_Activator.getDefault().getLog() .log(new Status(IStatus.ERROR, SATC_Activator.PLUGIN_ID, ex.getMessage(), ex)); } } protected void startSlicingOwnshipLegs(String contName) { // hey, let's also ditch any straight leg forecasts Iterator<BaseContribution> conts = activeSolver.getContributions().iterator(); ArrayList<BaseContribution> toRemove = new ArrayList<BaseContribution>(); while (conts.hasNext()) { BaseContribution baseC = conts.next(); if (baseC.isActive()) if (baseC instanceof StraightLegForecastContribution) { toRemove.add(baseC); } } // did we find any? if (!toRemove.isEmpty()) { Iterator<BaseContribution> iter = toRemove.iterator(); while (iter.hasNext()) { BaseContribution baseContribution = iter.next(); activeSolver.getContributions().removeContribution(baseContribution); } } // ok, clear any leg markers if (legPlot != null) { graphTabs.setSelection(legTab); legPlot.clearDomainMarkers(); } } protected void redoOwnshipStates() { if (legPlot == null) return; boolean showCourses = true; if (showOSCourse != null) showCourses = showOSCourse.getSelection(); java.awt.Color courseCol = java.awt.Color.blue.darker().darker(); java.awt.Color speedCol = java.awt.Color.blue.brighter().brighter(); // ok, now loop through and set them long startTime = Long.MAX_VALUE; long endTime = Long.MIN_VALUE; // clear any datasets legPlot.setDataset(0, null); legPlot.setDataset(1, null); // hmm, actually we have to remove any target leg markers @SuppressWarnings("unchecked") Collection<IntervalMarker> markers = legPlot.getDomainMarkers(Layer.BACKGROUND); if (markers != null) { ArrayList<IntervalMarker> markersToDelete = new ArrayList<IntervalMarker>(markers); Iterator<IntervalMarker> mIter = markersToDelete.iterator(); while (mIter.hasNext()) { IntervalMarker im = mIter.next(); legPlot.removeDomainMarker(im); } } // hey, does it have any ownship legs? TimeSeriesCollection tscC = new TimeSeriesCollection(); TimeSeriesCollection tscS = new TimeSeriesCollection(); TimeSeriesCollection tscCLegs = new TimeSeriesCollection(); TimeSeriesCollection tscSLegs = new TimeSeriesCollection(); TimeSeries courses = new TimeSeries("Course"); TimeSeries bearings = new TimeSeries("Bearings"); TimeSeries speeds = new TimeSeries("Speed"); TimeSeries courseLegs = new TimeSeries("Course (leg)"); TimeSeries speedLegs = new TimeSeries("Speed (leg)"); Iterator<BaseContribution> conts = activeSolver.getContributions().iterator(); while (conts.hasNext()) { BaseContribution baseC = conts.next(); if (baseC.isActive()) if (baseC instanceof BearingMeasurementContribution) { BearingMeasurementContribution bmc = (BearingMeasurementContribution) baseC; Iterator<LegOfData> lIter = null; LegOfData thisLeg = null; if (bmc.getOwnshipLegs() != null) { lIter = bmc.getOwnshipLegs().iterator(); thisLeg = lIter.next(); } List<HostState> hostStates = bmc.getHostState(); if (hostStates != null) { Iterator<HostState> stateIter = hostStates.iterator(); while (stateIter.hasNext()) { BearingMeasurementContribution.HostState hostState = stateIter.next(); long thisTime = hostState.time; double thisCourse = hostState.courseDegs; if (showCourses) courses.add(new FixedMillisecond(thisTime), thisCourse); double thisSpeed = hostState.speedKts; speeds.add(new FixedMillisecond(thisTime), thisSpeed); startTime = Math.min(thisTime, startTime); endTime = Math.max(thisTime, endTime); // sort out if this is in a leg or not if (thisLeg != null) { if (thisTime > thisLeg.getEnd() && lIter.hasNext()) { thisLeg = lIter.next(); } else { if (thisTime >= thisLeg.getStart()) { speedLegs.add(new FixedMillisecond(thisTime), thisSpeed); if (showCourses) courseLegs.add(new FixedMillisecond(thisTime), thisCourse); } } } } } // also, we wish to show the bearings from the BMC Iterator<BMeasurement> cuts = bmc.getMeasurements().iterator(); while (cuts.hasNext()) { BearingMeasurementContribution.BMeasurement measurement = cuts.next(); if (measurement.isActive()) { long thisT = measurement.getDate().getTime(); bearings.add(new FixedMillisecond(thisT), Math.toDegrees(Math.abs(measurement.getBearingRads()))); } } } } // HEY, also shade the ownship legs conts = activeSolver.getContributions().iterator(); while (conts.hasNext()) { BaseContribution baseC = conts.next(); if (baseC.isActive()) { if (baseC instanceof BearingMeasurementContribution) { BearingMeasurementContribution bmc = (BearingMeasurementContribution) baseC; Iterator<LegOfData> lIter = null; if (bmc.getOwnshipLegs() != null) { int ctr = 1; lIter = bmc.getOwnshipLegs().iterator(); while (lIter.hasNext()) { LegOfData thisL = lIter.next(); long thisStart = thisL.getStart(); long thisFinish = thisL.getEnd(); java.awt.Color transCol = new java.awt.Color(0, 0, 255, 12); final Marker bst = new IntervalMarker(thisStart, thisFinish, transCol, new BasicStroke(2.0f), null, null, 1.0f); bst.setLabel("O/S-" + ctr++); bst.setLabelAnchor(RectangleAnchor.TOP_LEFT); bst.setLabelFont(new Font("SansSerif", Font.ITALIC + Font.BOLD, 10)); bst.setLabelTextAnchor(TextAnchor.TOP_LEFT); legPlot.addDomainMarker(bst, Layer.BACKGROUND); } } } } } tscS.addSeries(speeds); tscSLegs.addSeries(speedLegs); tscC.addSeries(bearings); if (showCourses) { tscC.addSeries(courses); tscCLegs.addSeries(courseLegs); } legPlot.setDataset(0, null); legPlot.setDataset(1, null); legPlot.setDataset(2, null); legPlot.setDataset(3, null); legPlot.setDataset(0, tscC); legPlot.setDataset(1, tscS); legPlot.setDataset(2, tscCLegs); legPlot.setDataset(3, tscSLegs); final NumberAxis axis2 = new NumberAxis("Speed (Kts)"); legPlot.setRangeAxis(1, axis2); legPlot.mapDatasetToRangeAxis(1, 1); legPlot.mapDatasetToRangeAxis(3, 1); legPlot.getRangeAxis(0).setLabel("Crse/Brg (Degs)"); legPlot.mapDatasetToRangeAxis(0, 0); legPlot.mapDatasetToRangeAxis(2, 0); final XYLineAndShapeRenderer lineRenderer1 = new XYLineAndShapeRenderer(true, true); lineRenderer1.setSeriesPaint(1, courseCol); lineRenderer1.setSeriesShape(1, ShapeUtilities.createDiamond(0.1f)); lineRenderer1.setSeriesPaint(0, java.awt.Color.RED); lineRenderer1.setSeriesShape(0, ShapeUtilities.createDiamond(2f)); final XYLineAndShapeRenderer lineRenderer2 = new XYLineAndShapeRenderer(true, false); lineRenderer2.setSeriesPaint(0, speedCol); final XYLineAndShapeRenderer lineRenderer3 = new XYLineAndShapeRenderer(false, true); lineRenderer3.setSeriesPaint(0, courseCol); lineRenderer3.setSeriesShape(0, ShapeUtilities.createUpTriangle(2f)); final XYLineAndShapeRenderer lineRenderer4 = new XYLineAndShapeRenderer(false, true); lineRenderer4.setSeriesPaint(0, speedCol); lineRenderer4.setSeriesShape(0, ShapeUtilities.createDownTriangle(2f)); // ok, and store them legPlot.setRenderer(0, lineRenderer1); legPlot.setRenderer(1, lineRenderer2); legPlot.setRenderer(2, lineRenderer3); legPlot.setRenderer(3, lineRenderer4); if (startTime != Long.MAX_VALUE) legPlot.getDomainAxis().setRange(startTime, endTime); // ok - get the straight legs to sort themselves out // redoStraightLegs(); } protected void redoStraightLegs() { // ok, clear any leg markers if (legPlot != null) { if (!graphTabs.isDisposed()) graphTabs.setSelection(legTab); // hmm, actually we have to remove any target leg markers @SuppressWarnings("unchecked") Collection<IntervalMarker> markers = legPlot.getDomainMarkers(Layer.FOREGROUND); if (markers != null) { ArrayList<IntervalMarker> markersToDelete = new ArrayList<IntervalMarker>(markers); Iterator<IntervalMarker> mIter = markersToDelete.iterator(); while (mIter.hasNext()) { IntervalMarker im = mIter.next(); legPlot.removeDomainMarker(im); } } Iterator<BaseContribution> conts = activeSolver.getContributions().iterator(); while (conts.hasNext()) { BaseContribution baseC = conts.next(); if (baseC.isActive()) if (baseC instanceof StraightLegForecastContribution) { StraightLegForecastContribution slf = (StraightLegForecastContribution) baseC; java.awt.Color thisCol = slf.getColor(); // hmm, has it been given a color (initialised) yet? if (thisCol == null) continue; long thisStart = baseC.getStartDate().getTime(); long thisFinish = baseC.getFinishDate().getTime(); java.awt.Color transCol = new java.awt.Color(255, 0, 0, 22); final Marker bst = new IntervalMarker(thisStart, thisFinish, transCol, new BasicStroke(2.0f), null, null, 1.0f); bst.setLabel(baseC.getName()); bst.setLabelAnchor(RectangleAnchor.BOTTOM_LEFT); bst.setLabelFont(new Font("SansSerif", Font.ITALIC + Font.BOLD, 10)); bst.setLabelTextAnchor(TextAnchor.BASELINE_LEFT); legPlot.addDomainMarker(bst, Layer.FOREGROUND); } else { if (baseC instanceof BearingMeasurementContribution) { } } } } } protected void removeContribution(BaseContribution contribution, boolean doLayout) { BaseContributionView<?> panel = contributionsControl.get(contribution); if (panel != null) { panel.dispose(); contributionsControl.remove(contribution); if (doLayout) { contList.layout(); } } // aaah, is it a straight leg? if (contribution instanceof StraightLegForecastContribution) { stopListeningTo(contribution); // ok, better update the legs too. AAh, not if the form is closing if (doLayout) { redoStraightLegs(); } } else if (contribution instanceof BearingMeasurementContribution) { BearingMeasurementContribution bmc = (BearingMeasurementContribution) contribution; bmc.removeSliceListener(_sliceListener); } } @Override protected void finalize() throws Throwable { // clear our listeners Iterator<BaseContribution> conts = activeSolver.getContributions().iterator(); while (conts.hasNext()) { BaseContribution contribution = conts.next(); // aaah, is it a straight leg? if (contribution instanceof StraightLegForecastContribution) { stopListeningTo(contribution); } else if (contribution instanceof BearingMeasurementContribution) { BearingMeasurementContribution bmc = (BearingMeasurementContribution) contribution; bmc.removeSliceListener(_sliceListener); } } // let the parent shut down super.finalize(); } private void startListeningTo(final StraightLegForecastContribution slf) { slf.addPropertyChangeListener(BaseContribution.START_DATE, _legListener); slf.addPropertyChangeListener(BaseContribution.FINISH_DATE, _legListener); slf.addPropertyChangeListener(BaseContribution.NAME, _legListener); slf.addPropertyChangeListener(BaseContribution.ACTIVE, _legListener); } private void stopListeningTo(final BaseContribution slf) { slf.removePropertyChangeListener(BaseContribution.ACTIVE, _legListener); slf.removePropertyChangeListener(BaseContribution.START_DATE, _legListener); slf.removePropertyChangeListener(BaseContribution.FINISH_DATE, _legListener); slf.removePropertyChangeListener(BaseContribution.NAME, _legListener); } /** * copy the SATC scenario to the clipboard * */ protected void exportSATC() { // - ok, really we just export the state & bearing data if (activeSolver != null) { StringBuffer res = new StringBuffer(); final String newLine = System.getProperty("line.separator"); SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MMM/dd HH:mm:ss"); sdf.setTimeZone(TimeZone.getTimeZone("GMT")); @SuppressWarnings("deprecation") Date dateLead = new Date(100, 7, 7); Iterator<BaseContribution> conts = activeSolver.getContributions().iterator(); while (conts.hasNext()) { BaseContribution baseC = conts.next(); if (baseC instanceof BearingMeasurementContribution) { BearingMeasurementContribution bmc = (BearingMeasurementContribution) baseC; // ok - sort out the date offset Date startDate = bmc.getStartDate(); long offset = startDate.getTime() - dateLead.getTime(); // get ready for the offset Point2D origin = null; // get ready to calculate offsetes GeodeticCalculator calc = GeoSupport.createCalculator(); // ok, first the states res.append("//X, Y, Time, Course Degs, Speed Kts" + newLine); Iterator<HostState> states = bmc.getHostState().iterator(); while (states.hasNext()) { BearingMeasurementContribution.HostState hostState = states.next(); // sort out the X,Y offset double x, y; if (origin == null) { x = 0; y = 0; origin = new Point2D.Double(hostState.dLong, hostState.dLat); } else { // ok, calc a new XY, from the origin java.awt.geom.Point2D.Double thisP = new Point2D.Double(hostState.dLong, hostState.dLat); calc.setStartingGeographicPoint(origin); calc.setDestinationGeographicPoint(thisP); double angle = calc.getAzimuth(); double dist = calc.getOrthodromicDistance(); // and the new x,y coords x = Math.sin(Math.toRadians(angle)) * dist; y = Math.cos(Math.toRadians(angle)) * dist; } res.append(x + ", " + y + ", " + sdf.format(new Date(hostState.time - offset)) + "," + hostState.courseDegs + "," + hostState.speedKts + newLine); } // now the cuts res.append("//Time, Bearing Degs" + newLine); Iterator<BMeasurement> cuts = bmc.getMeasurements().iterator(); while (cuts.hasNext()) { BearingMeasurementContribution.BMeasurement cut = cuts.next(); res.append(sdf.format(new Date(cut.getDate().getTime() - offset)) + "," + Math.toDegrees(cut.getBearingRads()) + newLine); } } } // hmm, did we find anything if (res.length() > 0) { // ok, put it on the clipboard. new TextTransfer().setClipboardContents(res.toString()); } } } static final class TextTransfer implements ClipboardOwner { private TextTransfer() { } @Override public void lostOwnership(Clipboard aClipboard, Transferable aContents) { // do nothing } /** * Place a String on the clipboard, and make this class the owner of the * Clipboard's contents. */ public void setClipboardContents(String aString) { StringSelection stringSelection = new StringSelection(aString); Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); clipboard.setContents(stringSelection, this); } } }