/*****************************************************************************
* Limpet - the Lightweight InforMation ProcEssing Toolkit
* http://limpet.info
*
* (C) 2015-2016, Deep Blue C Technologies 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 info.limpet.ui.operations;
import info.limpet.ICommand;
import info.limpet.IContext;
import info.limpet.IOperation;
import info.limpet.IStore;
import info.limpet.IStoreGroup;
import info.limpet.IStoreItem;
import info.limpet.ITemporalObjectCollection;
import info.limpet.ITemporalQuantityCollection;
import info.limpet.data.commands.AbstractCommand;
import info.limpet.data.operations.CollectionComplianceTests;
import info.limpet.data.store.StoreGroup;
import info.limpet.stackedcharts.model.AngleAxis;
import info.limpet.stackedcharts.model.Chart;
import info.limpet.stackedcharts.model.ChartSet;
import info.limpet.stackedcharts.model.DataItem;
import info.limpet.stackedcharts.model.Dataset;
import info.limpet.stackedcharts.model.Datum;
import info.limpet.stackedcharts.model.DependentAxis;
import info.limpet.stackedcharts.model.IndependentAxis;
import info.limpet.stackedcharts.model.MarkerStyle;
import info.limpet.stackedcharts.model.Orientation;
import info.limpet.stackedcharts.model.PlainStyling;
import info.limpet.stackedcharts.model.ScatterSet;
import info.limpet.stackedcharts.model.SelectiveAnnotation;
import info.limpet.stackedcharts.model.StackedchartsFactory;
import info.limpet.stackedcharts.ui.view.StackedChartsView;
import info.limpet.ui.range_slider.RangeSliderView;
import java.awt.Color;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import javax.measure.Measurable;
import javax.measure.quantity.Quantity;
import javax.measure.unit.Unit;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IViewReference;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
public class ShowInTacticalOverview implements IOperation<IStoreItem>
{
private final CollectionComplianceTests aTests =
new CollectionComplianceTests();
private final String _title;
public ShowInTacticalOverview(String title)
{
_title = title;
}
protected CollectionComplianceTests getTests()
{
return aTests;
}
public Collection<ICommand<IStoreItem>> actionsFor(
List<IStoreItem> selection, IStore destination, IContext context)
{
Collection<ICommand<IStoreItem>> res =
new ArrayList<ICommand<IStoreItem>>();
if (appliesTo(selection))
{
ICommand<IStoreItem> newC =
new ShowInTacticalOverviewOperation(_title, selection, context);
res.add(newC);
}
return res;
}
protected boolean appliesTo(List<IStoreItem> selection)
{
boolean res = true;
boolean nonEmpty = aTests.nonEmpty(selection);
boolean isFolder = aTests.allGroups(selection);
boolean onlyOne = aTests.exactNumber(selection, 1);
if (nonEmpty && isFolder && onlyOne)
{
// ok, start looking deeper
StoreGroup sg = (StoreGroup) selection.get(0);
List<IStoreItem> children = sg;
Iterator<IStoreItem> iter = children.iterator();
while (iter.hasNext())
{
IStoreItem thisG = (IStoreItem) iter.next();
// check it's a group
if (thisG instanceof StoreGroup)
{
if (thisG.getName().equals("Primary"))
{
StoreGroup primary = (StoreGroup) thisG;
if (primary.size() != 3)
{
res = false;
break;
}
}
else if (thisG.getName().equals("Secondary"))
{
StoreGroup secondary = (StoreGroup) thisG;
if (secondary.size() != 3)
{
res = false;
break;
}
}
else if (thisG.getName().equals("Relative"))
{
StoreGroup relative = (StoreGroup) thisG;
if (relative.size() != 5)
{
res = false;
break;
}
}
else if (thisG.getName().equals("Sensor"))
{
// great, go for it
}
else
{
res = false;
break;
}
}
else
{
res = false;
break;
}
}
}
else
{
res = false;
}
return res;
}
public static class ShowInTacticalOverviewOperation extends
AbstractCommand<IStoreItem>
{
public ShowInTacticalOverviewOperation(String title,
List<IStoreItem> selection, IContext context)
{
super(title, "Show selection in Tactical Overview", null, false, false,
selection, context);
}
@Override
protected String getOutputName()
{
return null;
}
@Override
public void execute()
{
String secId = getInputs().toString();
String viewId = StackedChartsView.ID;
// create a new instance of the specified view
IWorkbenchWindow window =
PlatformUI.getWorkbench().getActiveWorkbenchWindow();
IWorkbenchPage page = window.getActivePage();
try
{
page.showView(viewId, secId, IWorkbenchPage.VIEW_ACTIVATE);
}
catch (PartInitException e)
{
e.printStackTrace();
}
// try to recover the view
IViewReference viewRef = page.findViewReference(viewId, secId);
if (viewRef != null)
{
IViewPart theView = viewRef.getView(true);
// double check it's what we're after
if (theView instanceof StackedChartsView)
{
final StackedChartsView cv = (StackedChartsView) theView;
// create the charts set model
ChartSet model = createModelFor(this.getInputs());
if (model != null)
{
// set follow selection to off
// cv.follow(getInputs());
cv.setModel(model);
// ok, also try to find the top level store
if (getInputs().size() > 0)
{
IStoreItem first = this.getInputs().get(0);
final IStoreGroup top = RangeSliderView.findTopParent(first);
if (top != null)
{
final PropertyChangeListener timeListener =
new PropertyChangeListener()
{
@Override
public void propertyChange(PropertyChangeEvent evt)
{
Date newTime = (Date) evt.getNewValue();
cv.updateTime(newTime);
}
};
// ok, register as listener
top.addTimeChangeListener(timeListener);
// we also need to drop it when the view is closing
cv.addRunOnCloseCallback(new Runnable()
{
@Override
public void run()
{
// ok, forget about it
top.removeTimeChangeListener(timeListener);
}
});
}
}
// // take a copy of the model
// URI resourceURI = URI.createFileURI("/home/ian/tacticalOverview.stackedcharts");
// Resource resource = new ResourceSetImpl().createResource(resourceURI);
// System.out.println("saving to:" + resourceURI.toFileString());
// resource.getContents().add(model);
// try
// {
// resource.save(null);
// }
// catch (IOException e)
// {
// e.printStackTrace();
// }
}
}
}
}
@Override
protected void recalculate(IStoreItem subject)
{
// don't worry
}
}
public static ChartSet createModelFor(List<IStoreItem> selection)
{
StackedchartsFactory factory = StackedchartsFactory.eINSTANCE;
ChartSet res = factory.createChartSet();
res.setOrientation(Orientation.VERTICAL);
IndependentAxis timeAxis = factory.createIndependentAxis();
// ok, make it a time axis
timeAxis.setAxisType(factory.createDateAxis());
res.setSharedAxis(timeAxis);
// ok, start looking deeper
StoreGroup sg = (StoreGroup) selection.get(0);
// create our state charts
Chart crsePlot = factory.createChart();
crsePlot.setName("Course");
DependentAxis crseAxis = factory.createDependentAxis();
AngleAxis crseAxisType = factory.createAngleAxis();
crseAxisType.setMinVal(0);
crseAxisType.setMaxVal(360);
crseAxis.setAxisType(crseAxisType);
crseAxis.setName("Course (Degs)");
crsePlot.getMinAxes().add(crseAxis);
res.getCharts().add(crsePlot);
Chart speedDepthPlot = factory.createChart();
speedDepthPlot.setName("Speed/Depth");
res.getCharts().add(speedDepthPlot);
DependentAxis speedAxis = factory.createDependentAxis();
speedAxis.setAxisType(factory.createNumberAxis());
speedAxis.setName("Speed (Kts)");
speedDepthPlot.getMinAxes().add(speedAxis);
DependentAxis depthAxis = factory.createDependentAxis();
depthAxis.setName("Depth (m)");
depthAxis.setAxisType(factory.createNumberAxis());
speedDepthPlot.getMaxAxes().add(depthAxis);
// create our range plot
Chart rangePlot = factory.createChart();
rangePlot.setName("Range");
DependentAxis rangeAxis = factory.createDependentAxis();
rangeAxis.setAxisType(factory.createNumberAxis());
rangeAxis.setName("Range (m)");
rangePlot.getMinAxes().add(rangeAxis);
res.getCharts().add(rangePlot);
List<IStoreItem> children = sg;
Iterator<IStoreItem> iter = children.iterator();
while (iter.hasNext())
{
IStoreItem thisG = (IStoreItem) iter.next();
// check it's a group
if (thisG instanceof StoreGroup)
{
if (thisG.getName().equals("Primary"))
{
StoreGroup primary = (StoreGroup) thisG;
createStateChart(factory, crseAxis, speedAxis, depthAxis, primary,
"Primary State", res, Color.blue);
}
else if (thisG.getName().equals("Secondary"))
{
StoreGroup primary = (StoreGroup) thisG;
createStateChart(factory, crseAxis, speedAxis, depthAxis, primary,
"Secondary State", res, Color.red);
}
else if (thisG.getName().equals("Relative"))
{
StoreGroup relative = (StoreGroup) thisG;
if (relative.size() == 5)
{
// ok, create the primary chart
Chart relativeChart = factory.createChart();
relativeChart.setName("Relative");
res.getCharts().add(relativeChart);
DependentAxis brgAxis = factory.createDependentAxis();
brgAxis.setName("Bearing");
brgAxis.setAxisType(factory.createNumberAxis());
relativeChart.getMinAxes().add(brgAxis);
DependentAxis redGreenAxis = factory.createDependentAxis();
redGreenAxis.setName("Relative/ATB");
AngleAxis redGreenAngle = factory.createAngleAxis();
redGreenAngle.setMinVal(-180);
redGreenAngle.setMaxVal(180);
redGreenAngle.setRedGreen(true);
redGreenAngle.setMidOrigin(true);
redGreenAxis.setAxisType(redGreenAngle);
relativeChart.getMinAxes().add(redGreenAxis);
DependentAxis brgRateAxis = factory.createDependentAxis();
brgRateAxis.setName("Bearing Rate");
brgRateAxis.setAxisType(factory.createNumberAxis());
relativeChart.getMinAxes().add(brgRateAxis);
// now sort out the data series
Iterator<IStoreItem> dIter = relative.iterator();
while (dIter.hasNext())
{
IStoreItem iStoreItem = (IStoreItem) dIter.next();
if (iStoreItem.getName().equals("Range"))
{
createDataset(factory, iStoreItem, "Range", rangeAxis, res,
Color.red, MarkerStyle.NONE, false);
}
else if (iStoreItem.getName().equals("Bearing"))
{
createDataset(factory, iStoreItem, "Bearing", brgAxis, res,
Color.green, MarkerStyle.NONE, true);
}
else if (iStoreItem.getName().equals("Rel Brg"))
{
createDataset(factory, iStoreItem, "Rel Brg", redGreenAxis, res,
Color.orange, MarkerStyle.NONE, true);
}
else if (iStoreItem.getName().equals("ATB"))
{
createDataset(factory, iStoreItem, "ATB", redGreenAxis, res, Color.blue,
MarkerStyle.NONE, true);
}
else if (iStoreItem.getName().equals("Brg Rate"))
{
createDataset(factory, iStoreItem, "Brg Rate", brgRateAxis,
res, Color.cyan, MarkerStyle.NONE, true);
}
}
}
}
else if (thisG.getName().equals("Sensor"))
{
StoreGroup sensor = (StoreGroup) thisG;
for (IStoreItem coll : sensor)
{
ScatterSet scatter = factory.createScatterSet();
@SuppressWarnings("unchecked")
ITemporalObjectCollection<Object> cuts =
(ITemporalObjectCollection<Object>) coll;
// name the scatter set
scatter.setName(cuts.getName());
Iterator<Long> times = cuts.getTimes().iterator();
while (times.hasNext())
{
Long long1 = (Long) times.next();
Datum item = factory.createDatum();
item.setVal(long1);
scatter.getDatums().add(item);
}
SelectiveAnnotation sel = factory.createSelectiveAnnotation();
sel.setAnnotation(scatter);
sel.getAppearsIn().add(
res.getCharts().get(res.getCharts().size() - 1));
timeAxis.getAnnotations().add(sel);
}
}
}
}
return res;
}
protected static void createStateChart(StackedchartsFactory factory,
DependentAxis crseAxis, DependentAxis speedAxis, DependentAxis depthAxis,
StoreGroup group, String chartName, ChartSet set, java.awt.Color color)
{
if (group.size() == 3)
{
// now sort out the data series
Iterator<IStoreItem> dIter = group.iterator();
while (dIter.hasNext())
{
IStoreItem iStoreItem = (IStoreItem) dIter.next();
final String thisName = iStoreItem.getName();
if (thisName.contains("Course"))
{
createDataset(factory, iStoreItem, thisName, crseAxis, set, color,
MarkerStyle.NONE, false);
}
else if (thisName.contains("Speed"))
{
createDataset(factory, iStoreItem, thisName, speedAxis, set, color
.brighter().brighter(), MarkerStyle.CROSS, true);
}
else if (thisName.contains("Depth"))
{
createDataset(factory, iStoreItem, thisName, depthAxis, set, color
.darker().darker(), MarkerStyle.DIAMOND, true);
}
}
}
}
protected static void createDataset(StackedchartsFactory factory,
IStoreItem iStoreItem, String name, DependentAxis axis,
ChartSet chartSet, java.awt.Color color, MarkerStyle marker,
boolean showInLegend)
{
ITemporalQuantityCollection<?> it =
(ITemporalQuantityCollection<?>) iStoreItem;
List<Long> times = it.getTimes();
List<?> values = it.getValues();
Dataset newD = factory.createDataset();
newD.setName(name);
PlainStyling styling = factory.createPlainStyling();
styling.setColor(color);
styling.setMarkerStyle(marker);
styling.setIncludeInLegend(showInLegend);
styling.setLineThickness(2d);
newD.setStyling(styling);
for (int i = 0; i < times.size(); i++)
{
double time = times.get(i);
@SuppressWarnings("unchecked")
Measurable<Quantity> quantity = (Measurable<Quantity>) values.get(i);
@SuppressWarnings("unchecked")
double value = quantity.doubleValue((Unit<Quantity>) it.getUnits());
DataItem newI = factory.createDataItem();
newI.setDependentVal(value);
newI.setIndependentVal(time);
newD.getMeasurements().add(newI);
}
// and it to an axis
axis.getDatasets().add(newD);
}
}