/****************************************************************************** * This file is protected by Copyright. * Please refer to the COPYRIGHT file distributed with this source distribution. * * This file is part of REDHAWK IDE. * * All rights reserved. This program and the accompanying materials are made available under * the terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html *******************************************************************************/ package gov.redhawk.statistics.ui.views; import gov.redhawk.statistics.ui.internal.CustomAction; import gov.redhawk.statistics.ui.internal.DatalistDataset; import gov.redhawk.statistics.ui.internal.SettingsDialog; import gov.redhawk.statistics.ui.internal.Stats; import java.awt.Color; import java.awt.Frame; import java.awt.GridLayout; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.jface.window.Window; import org.eclipse.swt.SWT; import org.eclipse.swt.awt.SWT_AWT; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.Section; import org.eclipse.ui.part.ViewPart; import org.eclipse.ui.progress.WorkbenchJob; import org.jfree.chart.ChartColor; import org.jfree.chart.ChartFactory; import org.jfree.chart.ChartPanel; import org.jfree.chart.JFreeChart; import org.jfree.chart.labels.XYItemLabelGenerator; import org.jfree.chart.labels.XYSeriesLabelGenerator; import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.renderer.xy.ClusteredXYBarRenderer; import org.jfree.chart.renderer.xy.StandardXYBarPainter; import org.jfree.data.general.DatasetChangeEvent; import org.jfree.data.general.DatasetChangeListener; import org.jfree.data.xy.XYDataset; public class StatisticsView extends ViewPart { public static final String ID = "gov.redhawk.statistics.ui.views.StatisticsView"; public static final String[] STAT_PROPS = { Stats.MINIMUM, Stats.MAXIMUM, Stats.MEDIAN, Stats.MEAN, Stats.STD_DEV, Stats.NUM }; private Label[] labels = new Label[STAT_PROPS.length]; private Number[][] datalist; private JFreeChart chart; private Stats[] stats; private Stats magnitudeStats; private Composite parent; private Section section; private DatalistDataset dataSet = new DatalistDataset(); private int curIndex = -1; private int numBars = 4; private final List<DisposeListener> listeners = Collections.synchronizedList(new ArrayList<DisposeListener>()); private WorkbenchJob refreshJob = new WorkbenchJob("Refreshing Data and Composite") { { setSystem(true); setUser(false); } @Override public IStatus runInUIThread(IProgressMonitor monitor) { refresh(); return Status.OK_STATUS; } }; /** * the constructor */ public StatisticsView() { } /** * This is a callback that will allow us to create the viewer and initialize it. */ @Override public void createPartControl(Composite comp) { parent = comp; parent.setLayout(GridLayoutFactory.fillDefaults().margins(10, 10).numColumns(1).create()); // Custom Action for the View's Menu CustomAction customAction = new CustomAction() { @Override public void run() { SettingsDialog dialog = new SettingsDialog(parent.getShell(), datalist.length, curIndex, numBars); dialog.create(); if (dialog.open() == Window.OK) { numBars = dialog.getNumBars(); curIndex = dialog.getSelectedIndex(); refreshJob.schedule(); } } }; customAction.setText("Settings"); getViewSite().getActionBars().getMenuManager().add(customAction); // creation of chart composite and selection of associated options Composite chartComposite = new Composite(parent, SWT.EMBEDDED); chartComposite.setLayoutData(GridDataFactory.fillDefaults().grab(true, true).create()); chart = ChartFactory.createXYBarChart(null, null, false, null, dataSet, PlotOrientation.VERTICAL, false, true, false); org.eclipse.swt.graphics.Color backgroundColor = chartComposite.getBackground(); chart.setBackgroundPaint(new Color(backgroundColor.getRed(), backgroundColor.getGreen(), backgroundColor.getBlue())); chart.getXYPlot().setBackgroundPaint(ChartColor.WHITE); Frame chartFrame = SWT_AWT.new_Frame(chartComposite); chartFrame.setBackground(new Color(backgroundColor.getRed(), backgroundColor.getGreen(), backgroundColor.getBlue())); chartFrame.setLayout(new GridLayout()); ChartPanel jFreeChartPanel = new ChartPanel(chart); chartFrame.add(jFreeChartPanel); ClusteredXYBarRenderer renderer = new ClusteredXYBarRenderer(); renderer.setBarPainter(new StandardXYBarPainter()); renderer.setMargin(0.05); renderer.setShadowVisible(false); renderer.setBaseItemLabelsVisible(true); renderer.setBaseItemLabelGenerator(new XYItemLabelGenerator() { @Override public String generateLabel(XYDataset dataset, int series, int item) { return String.valueOf((int) (dataset.getYValue(series, item))); } }); renderer.setBasePaint(new Color(139, 0, 0)); renderer.setLegendItemLabelGenerator(new XYSeriesLabelGenerator() { @Override public String generateLabel(XYDataset ds, int i) { if (ds.getSeriesCount() == 2) { if (i == 0) { return "Real"; } else if (i == 1) { return "Imaginary"; } else { return "Complex"; } } else if (ds.getSeriesCount() > 1) { return "Dimension " + i; } return null; } }); chart.getXYPlot().setRenderer(renderer); dataSet.addChangeListener(new DatasetChangeListener() { @Override public void datasetChanged(DatasetChangeEvent event) { chart.getPlot().datasetChanged(event); } }); // creation of the statistics composite FormToolkit toolkit = new FormToolkit(parent.getDisplay()); section = toolkit.createSection(parent, Section.DESCRIPTION | Section.NO_TITLE | Section.CLIENT_INDENT); section.setBackground(parent.getBackground()); section.setDescription(""); section.setLayoutData(GridDataFactory.fillDefaults().grab(true, false).create()); // layout within parent // Composite for storing the data Composite composite = toolkit.createComposite(section, SWT.WRAP); composite.setBackground(parent.getBackground()); composite.setLayout(GridLayoutFactory.fillDefaults().margins(10, 10).numColumns(4).create()); composite.setLayoutData(GridDataFactory.fillDefaults().grab(true, false).create()); // layout within parent toolkit.paintBordersFor(composite); section.setClient(composite); for (int j = 0; j < STAT_PROPS.length; j++) { Label label = new Label(composite, SWT.None); label.setText(STAT_PROPS[j] + ":"); labels[j] = new Label(composite, SWT.None); labels[j].setLayoutData(GridDataFactory.fillDefaults().grab(true, false).create()); } } private void refresh() { Job job = new Job("Update Chart..") { @Override protected IStatus run(IProgressMonitor monitor) { createStatsArray(); PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() { @Override public void run() { updateStatsLabels(curIndex); } }); setAllCategories(); return Status.OK_STATUS; } }; job.schedule(); } private void createStatsArray() { stats = new Stats[datalist.length]; for (int i = 0; i < stats.length; i++) { stats[i] = new Stats(datalist[i]); } magnitudeStats = new Stats(magArray()); } private void updateStatsLabels(int i) { int showIndex = i; if (datalist.length == 1) { showIndex = 0; } Stats s; if (showIndex < 0) { s = magnitudeStats; } else { s = stats[showIndex]; } for (int j = 0; j < STAT_PROPS.length; j++) { DecimalFormat form; double value = s.getStat(STAT_PROPS[j]).doubleValue(); if (STAT_PROPS[j].equals(Stats.NUM)) { form = new DecimalFormat(); } else if (value != 0 && (Math.abs(value) * 10 < 1 || Math.abs(value) / 10 > 99)) { form = new DecimalFormat("0.0#E0"); } else { form = new DecimalFormat(); form.setMaximumFractionDigits(3); form.setMaximumIntegerDigits(2); } labels[j].setText(form.format(value)); } section.setDescription(getCategoryName(showIndex)); } private void setAllCategories() { dataSet.removeAllSeries(); if (curIndex >= 0) { dataSet.addSeries(getCategoryName(curIndex), doubleArray(curIndex), numBars); } else { for (int i = 0; i < datalist.length; i++) { dataSet.addSeries(getCategoryName(i), doubleArray(i), numBars); } } } private String getCategoryName(int i) { if (i < 0) { return "Complex (statistics calculated using magnitude)"; } else if (datalist.length == 2) { if (i == 0) { return "Real"; } else { return "Imaginary"; } } else if (datalist.length == 1) { return ""; } return "Dimension " + i; } /** * @since 2.0 */ public void setInput(Number[][] datalist) { this.datalist = datalist; refreshJob.schedule(); } private double[] doubleArray(int index) { Number[] series = datalist[index]; double[] array = new double[series.length]; for (int i = 0; i < array.length; i++) { array[i] = series[i].doubleValue(); } return array; } private Number[] magArray() { Number[] array = new Number[datalist.length]; for (int i = 0; i < datalist.length; i++) { array[i] = findMagnitude(datalist[i]); } return array; } private Number findMagnitude(Number[] nums) { double n = 0; for (int i = 0; i < nums.length; i++) { n += Math.pow(nums[i].doubleValue(), 2); } return Math.sqrt(n); } public void setIndex(int i) { this.curIndex = i; refreshJob.schedule(); } public void setNumBars(int i) { this.numBars = i; } /** * Passing the focus request to the viewer's control. */ @Override public void setFocus() { } @Override public void dispose() { super.dispose(); for (DisposeListener listener : listeners) { listener.widgetDisposed(null); } } public void addDisposeListener(DisposeListener listener) { if (listeners.contains(listener)) { return; } listeners.add(listener); } public void removeDisposeListener(DisposeListener listener) { if (listeners.contains(listener)) { listeners.remove(listener); } } }