/******************************************************************************
* 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.datalist.ui.views;
import gov.redhawk.datalist.ui.DataCollectionSettings;
import gov.redhawk.datalist.ui.DataListPlugin;
import gov.redhawk.datalist.ui.Sample;
import gov.redhawk.datalist.ui.internal.DataCourier;
import gov.redhawk.datalist.ui.internal.DataCourierReceiver;
import gov.redhawk.datalist.ui.internal.IDataCourierListener;
import gov.redhawk.ide.snapshot.ui.SnapshotJob;
import gov.redhawk.ide.snapshot.ui.SnapshotWizard;
import gov.redhawk.model.sca.ScaAbstractComponent;
import gov.redhawk.model.sca.ScaUsesPort;
import gov.redhawk.model.sca.ScaWaveform;
import java.lang.reflect.Array;
import java.text.DecimalFormat;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.layout.TableColumnLayout;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ColumnPixelData;
import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.ILazyContentProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.ProgressBar;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.progress.WorkbenchJob;
import org.eclipse.ui.statushandlers.StatusManager;
import BULKIO.PrecisionUTCTime;
/**
* @since 2.0
*/
public class DataListView extends ViewPart {
/**
* The ID of the view as specified by the extension.
*/
public static final String ID = "gov.redhawk.datalist.ui.views.DataListView";
public static final String REAL = "Real Value", IMAGINARY = "Imaginary Value", COMPLEX = "Complex";
private final DataCourier dataCourier;
private OptionsComposite input;
private TableViewer viewer;
private Button chartButton, snapshotButton;
private ProgressBar loading;
private Composite tableComposite;
private int prevCols;
private int selectedIndex;
private class ViewContentProvider implements ILazyContentProvider {
private TableViewer viewer;
private DataCourier data;
private IDataCourierListener listener = new IDataCourierListener() {
private WorkbenchJob completeJob = new WorkbenchJob("Refresh Viewer...") {
{
setUser(false);
setSystem(true);
}
@Override
public IStatus runInUIThread(IProgressMonitor monitor) {
if (DataListView.this.viewer != null && !DataListView.this.viewer.getControl().isDisposed()) {
stopAcquire();
updateViewer();
}
return Status.OK_STATUS;
}
};
@Override
public void dataChanged() {
}
@Override
public void complete() {
completeJob.schedule(100);
}
};
private void updateViewer() {
BusyIndicator.showWhile(null, new Runnable() {
@Override
public void run() {
viewer.setItemCount(data.getBuffer().size());
}
});
}
@Override
public void inputChanged(final Viewer v, final Object oldInput, final Object newInput) {
viewer = (TableViewer) v;
if (newInput instanceof DataCourier) {
data = (DataCourier) newInput;
data.addListener(listener);
}
if (oldInput instanceof DataCourier) {
((DataCourier) oldInput).removeListener(listener);
}
updateViewer();
}
@Override
public void dispose() {
}
@Override
public void updateElement(int index) {
viewer.replace(data.getBuffer().get(index), index);
}
}
private abstract static class PrecisionTimeTooltipProvider extends ColumnLabelProvider {
@Override
public int getToolTipDisplayDelayTime(final Object object) {
return 50;
}
@Override
public int getToolTipTimeDisplayed(final Object object) {
return 5000;
}
@Override
public String getToolTipText(final Object element) {
if (element instanceof Sample) {
final Sample s = (Sample) element;
final PrecisionUTCTime time = s.getTime();
return "TC Mode: " + time.tcmode + "\n" + "TC Status: " + time.tcstatus + "\n" + "TF Sec: " + time.tfsec + "\n" + "T Off: " + time.toff + "\n"
+ "TW Sec: " + time.twsec;
}
return super.getToolTipText(element);
}
}
private static class IndexColumnLabelProvider extends PrecisionTimeTooltipProvider {
@Override
public String getText(final Object element) {
if (element instanceof Sample) {
final Sample s = (Sample) element;
return String.valueOf(s.getIndex());
}
return super.getText(element);
}
}
private class ValueColumnLabelProvider extends PrecisionTimeTooltipProvider {
private final int index;
public ValueColumnLabelProvider(final int index) {
this.index = index;
}
@Override
public String getText(final Object element) {
if (element instanceof Sample) {
final Sample s = (Sample) element;
final Object data = s.getData();
Object value = null;
if (data.getClass().isArray()) {
if (Array.getLength(data) > this.index) {
value = Array.get(data, this.index);
} else {
return "";
}
} else {
value = data;
}
DecimalFormat form;
if (value != null && value instanceof Number) {
double doubleValue = ((Number) value).doubleValue();
if (doubleValue != 0 && (Math.abs(doubleValue) * 10 < 1 || Math.abs(doubleValue) / 10 > 99)) {
form = new DecimalFormat("0.0#E0");
} else {
form = new DecimalFormat();
form.setMaximumFractionDigits(3);
form.setMaximumIntegerDigits(2);
}
return form.format(value);
}
}
return super.getText(element);
}
}
/**
* The constructor.
*/
public DataListView() {
dataCourier = new DataCourier();
}
/**
* This is a callback that will allow us
* to create the viewer and initialize it.
*/
@Override
public void createPartControl(final Composite parent) {
parent.setLayout(GridLayoutFactory.fillDefaults().margins(5, 10).numColumns(1).create());
input = new OptionsComposite(parent) {
@Override
public void startAcquire() {
DataListView.this.startAcquire(this.getSettings());
}
@Override
public void stopAcquire() {
DataListView.this.stopAcquire();
}
};
this.tableComposite = new Composite(parent, SWT.None);
this.tableComposite.setLayoutData(GridDataFactory.fillDefaults().grab(true, true).create());
createTable(1);
Composite bottom = new Composite(parent, SWT.None);
bottom.setLayoutData(GridDataFactory.fillDefaults().grab(true, false).create());
bottom.setLayout(GridLayoutFactory.fillDefaults().numColumns(3).create());
loading = new ProgressBar(bottom, SWT.HORIZONTAL | SWT.INDETERMINATE);
loading.setVisible(false);
loading.setLayoutData(GridDataFactory.fillDefaults().align(SWT.LEFT, SWT.CENTER).grab(true, false).create());
snapshotButton = new Button(bottom, SWT.None);
snapshotButton.setText("Save");
snapshotButton.setLayoutData(GridDataFactory.fillDefaults().align(SWT.RIGHT, SWT.CENTER).create());
snapshotButton.setImage(DataListPlugin.imageDescriptorFromPlugin(DataListPlugin.PLUGIN_ID, "icons/save.gif").createImage());
snapshotButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
SnapshotWizard wizard = new SnapshotWizard();
WizardDialog dialog = new WizardDialog(parent.getShell(), wizard);
dialog.open();
DataCourierReceiver receiver = new DataCourierReceiver(dataCourier);
receiver.setDataWriter(wizard.getDataWriter());
SnapshotJob job = new SnapshotJob("Data list snapshot", receiver);
job.schedule();
}
});
chartButton = new Button(bottom, SWT.None);
chartButton.setImage(DataListPlugin.imageDescriptorFromPlugin(DataListPlugin.PLUGIN_ID, "icons/chart.gif").createImage());
chartButton.setText("Chart");
chartButton.setToolTipText("Chart Data List");
chartButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
dataCourier.openStatisticsView(String.valueOf(hashCode()));
}
});
chartButton.setLayoutData(GridDataFactory.fillDefaults().align(SWT.RIGHT, SWT.CENTER).create());
chartButton.setEnabled(false);
snapshotButton.setEnabled(false);
}
protected void createTable(final int numColumns) {
if (this.viewer != null) {
this.viewer.getTable().dispose();
this.viewer = null;
}
final TableColumnLayout layout = new TableColumnLayout();
this.tableComposite.setLayout(layout);
this.viewer = new TableViewer(this.tableComposite, SWT.BORDER | SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.VIRTUAL | SWT.FULL_SELECTION);
this.viewer.setContentProvider(new ViewContentProvider());
this.viewer.getTable().setHeaderVisible(true);
this.viewer.getTable().setLinesVisible(true);
this.viewer.setUseHashlookup(true);
ColumnViewerToolTipSupport.enableFor(this.viewer);
final TableViewerColumn indexColumn = new TableViewerColumn(this.viewer, SWT.CENTER);
indexColumn.getColumn().setText("Sample ID");
indexColumn.getColumn().setResizable(true);
indexColumn.getColumn().setMoveable(false);
indexColumn.getColumn().setWidth(50);
indexColumn.getColumn().addSelectionListener(new SelectionListener() {
/**
* Called when the index column's header is selected.
*/
@Override
public void widgetSelected(SelectionEvent e) {
selectedIndex = DataCourier.ALL;
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {
}
});
indexColumn.setLabelProvider(new IndexColumnLabelProvider());
layout.setColumnData(indexColumn.getColumn(), new ColumnPixelData(100, true));
for (int i = 0; i < numColumns; i++) {
final TableViewerColumn dataColumn = new TableViewerColumn(this.viewer, SWT.CENTER);
dataColumn.getColumn().setText("Value [" + i + "]");
dataColumn.getColumn().setResizable(true);
dataColumn.getColumn().setMoveable(false);
dataColumn.getColumn().setWidth(75);
dataColumn.getColumn().setData(i); // i is the dimension of the data w/in this column
if (numColumns == 2) {
if (i == 0) {
dataColumn.getColumn().setText(REAL);
} else {
dataColumn.getColumn().setText(IMAGINARY);
}
}
dataColumn.getColumn().addSelectionListener(new SelectionListener() {
/**
* Called when the column header is selected.
*/
@Override
public void widgetSelected(SelectionEvent e) {
selectedIndex = (Integer) dataColumn.getColumn().getData();
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {
}
});
dataColumn.setLabelProvider(new ValueColumnLabelProvider(i));
layout.setColumnData(dataColumn.getColumn(), new ColumnWeightData(100, 75, true));
}
this.viewer.getControl().setLayoutData(GridDataFactory.fillDefaults().grab(true, true).span(6, 1).create());
this.viewer.setInput(dataCourier);
tableComposite.layout(true);
}
protected void startAcquire(DataCollectionSettings settings) {
ScaUsesPort source = dataCourier.getSource();
if (source == null || source.isDisposed()) {
StatusManager.getManager().handle(
new Status(Status.ERROR, DataListPlugin.PLUGIN_ID, "No source or source is no longer valid.", new Exception().fillInStackTrace()),
StatusManager.SHOW);
chartButton.setEnabled(false);
snapshotButton.setEnabled(false);
loading.setVisible(false);
input.getButton().setEnabled(false);
return;
} else {
EObject container = source.eContainer();
Boolean started = null;
if (container instanceof ScaAbstractComponent< ? >) {
ScaAbstractComponent< ? > comp = (ScaAbstractComponent< ? >) container;
started = comp.getStarted();
} else if (container instanceof ScaWaveform) {
ScaWaveform waveform = (ScaWaveform) container;
started = waveform.getStarted();
}
if (started == null || !started) {
boolean result = MessageDialog.openQuestion(Display.getCurrent().getActiveShell(), "Started?",
"Attempting to accquire data from a stopped resource will generally wait forever. \n\nDo you wish to continue?");
if (!result) {
return;
}
}
}
int columns = settings.getDimensions();
if (prevCols != columns) {
createTable(columns);
prevCols = columns;
}
dataCourier.acquire(settings);
viewer.setItemCount(0);
setButtons(true); // is running
}
private void stopAcquire() {
dataCourier.stop();
setButtons(false); // is no longer running
}
public void setButtons(boolean running) {
chartButton.setEnabled(!running);
snapshotButton.setEnabled(!running);
loading.setVisible(running);
if (input != null) {
input.buttonsEnable(running);
}
}
@Override
public void dispose() {
super.dispose();
if (this.dataCourier != null) {
this.dataCourier.dispose();
}
}
public void setInput(final ScaUsesPort port) {
try {
dataCourier.setSource(port);
} catch (final Exception e) { // SUPPRESS CHECKSTYLE Logged Catch all exception
setContentDescription(e.getMessage());
if (this.viewer != null) {
this.viewer.getControl().setEnabled(false);
}
}
}
/**
* Passing the focus request to the viewer's control.
*/
@Override
public void setFocus() {
if (this.input != null) {
this.input.setFocus();
}
}
}