/**
* 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.bulkio.ui.views;
import gov.redhawk.bulkio.ui.BulkIOUIActivator;
import gov.redhawk.bulkio.ui.internal.SriDataViewContentProvider;
import gov.redhawk.bulkio.ui.internal.SriDataViewLabelProvider;
import gov.redhawk.bulkio.ui.internal.SriDataViewReceiver;
import gov.redhawk.bulkio.ui.internal.SriWrapper;
import gov.redhawk.bulkio.ui.writer.SriFileWriter;
import gov.redhawk.bulkio.ui.writer.SriXmlWriter;
import gov.redhawk.bulkio.util.BulkIOType;
import gov.redhawk.model.sca.IDisposable;
import gov.redhawk.model.sca.ScaComponent;
import gov.redhawk.model.sca.ScaPackage;
import gov.redhawk.model.sca.ScaUsesPort;
import gov.redhawk.model.sca.ScaWaveform;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.impl.AdapterImpl;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.ActionContributionItem;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuCreator;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.layout.TreeColumnLayout;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
import org.eclipse.ui.statushandlers.StatusManager;
public class SriDataView extends ViewPart {
public static final String ID = "gov.redhawk.bulkio.ui.sridata.view";
private TreeViewer viewer;
private TreeColumnLayout treeLayout;
private SriDataViewContentProvider contentProvider;
private SriDataViewReceiver sriReceiver;
private Map<String, SriWrapper> streamMap;
private SwitchStreamMenuAction switchStreamAction;
private IAction clearTerminatedAction;
private IAction clearAllTerminatedAction;
private IAction getNotificationsAction;
private IAction pauseSri;
private IAction saveSriToFile;
private boolean notifyOnChanged = true;
private boolean paused = false;
private boolean terminatedStreams = true;
private Adapter portListener = new AdapterImpl() {
@Override
public void notifyChanged(final Notification msg) {
Display.getDefault().syncExec(new Runnable() {
@Override
public void run() {
switch (msg.getFeatureID(IDisposable.class)) {
case ScaPackage.IDISPOSABLE__DISPOSED:
getSite().getPage().hideView(SriDataView.this);
break;
default:
break;
}
}
});
}
};
@Override
public void createPartControl(Composite root) {
final Composite parent = new Composite(root, SWT.None);
this.viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION);
this.viewer.setUseHashlookup(true);
this.viewer.getTree().setHeaderVisible(true);
this.viewer.getTree().setLinesVisible(true);
this.treeLayout = new TreeColumnLayout();
parent.setLayout(treeLayout);
initializeColumns();
contentProvider = new SriDataViewContentProvider();
this.viewer.setContentProvider(contentProvider);
this.viewer.setLabelProvider(new SriDataViewLabelProvider());
createActions();
createToolBars();
}
private void initializeColumns() {
TreeColumn nameColumn = new TreeColumn(viewer.getTree(), SWT.NONE);
nameColumn.setWidth(100);
nameColumn.setText("Property: ");
treeLayout.setColumnData(nameColumn, new ColumnWeightData(20, 50));
TreeColumn valueColumn = new TreeColumn(viewer.getTree(), SWT.NONE);
valueColumn.setWidth(200);
valueColumn.setText("Value: ");
treeLayout.setColumnData(valueColumn, new ColumnWeightData(80, 100));
}
private void createToolBars() {
final IActionBars bars = getViewSite().getActionBars();
final IToolBarManager toolBarManager = bars.getToolBarManager();
if (clearTerminatedAction != null) {
if (!terminatedStreams) {
this.clearTerminatedAction.setEnabled(false);
} else {
this.clearTerminatedAction.setEnabled(true);
}
toolBarManager.add(this.clearTerminatedAction);
}
if (clearAllTerminatedAction != null) {
toolBarManager.add(this.clearAllTerminatedAction);
}
toolBarManager.add(new Separator());
if (pauseSri != null) {
toolBarManager.add(this.pauseSri);
}
if (getNotificationsAction != null) {
toolBarManager.add(this.getNotificationsAction);
}
if (switchStreamAction != null) {
toolBarManager.add(this.switchStreamAction);
}
if (saveSriToFile != null) {
toolBarManager.add(this.saveSriToFile);
}
toolBarManager.add(new Separator());
toolBarManager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
}
private void createActions() {
//Drop-down action that holds a list of actions to use when switching between multiple streams
this.switchStreamAction = new SwitchStreamMenuAction();
final ImageDescriptor switchStreamImageDescriptor = AbstractUIPlugin.imageDescriptorFromPlugin(BulkIOUIActivator.PLUGIN_ID, "icons/sri.gif");
this.switchStreamAction.setImageDescriptor(switchStreamImageDescriptor);
//Action to turn on or off notification of a change in the SRI content (bolding of the tab text)
this.getNotificationsAction = new Action("Notify on receiving new Push SRI", IAction.AS_CHECK_BOX) {
@Override
public void run() {
if (notifyOnChanged) {
notifyOnChanged = false;
} else {
notifyOnChanged = true;
}
}
};
this.getNotificationsAction.setEnabled(true);
final ImageDescriptor getNotificationsImageDescriptor = AbstractUIPlugin.imageDescriptorFromPlugin(BulkIOUIActivator.PLUGIN_ID,
"icons/sri_updating.gif");
this.getNotificationsAction.setImageDescriptor(getNotificationsImageDescriptor);
//Action to pause/un-pause reception of new data
this.pauseSri = new Action("Pause incoming SRI data", IAction.AS_CHECK_BOX) {
@Override
public void run() {
if (paused) {
paused = false;
sriReceiver.updateViewStreamMap();
} else {
paused = true;
sriReceiver.updateViewStreamMap();
}
}
};
this.pauseSri.setEnabled(true);
final ImageDescriptor pauseSriImageDescriptor = AbstractUIPlugin.imageDescriptorFromPlugin(BulkIOUIActivator.PLUGIN_ID, "icons/sri_pause.gif");
this.pauseSri.setImageDescriptor(pauseSriImageDescriptor);
//Action to save SRI data to file
this.saveSriToFile = new Action("Save SRI Data to file", IAction.AS_PUSH_BUTTON) {
@Override
public void run() {
Shell parent = getSite().getShell();
FileDialog saveDialog = new FileDialog(parent, SWT.SAVE | SWT.CANCEL);
saveDialog.setText("Save SRI to File");
String saveLocation = saveDialog.open();
Map<String, SriWrapper> streamMapToSave = sriReceiver.getStreamMap();
List<String> filesWritten = new ArrayList<String>();
SriFileWriter sriWriter = new SriFileWriter();
SriXmlWriter xmlWriter = new SriXmlWriter();
try {
String nl = System.getProperty("line.separator");
BulkIOType bulkioType = sriReceiver.getBulkIOType();
sriWriter.performSave(streamMapToSave, saveLocation, bulkioType, parent);
for (String filename : sriWriter.getFilesWritten()) {
filesWritten.add(nl + filename);
}
xmlWriter.performSave(streamMapToSave, saveLocation, bulkioType, parent);
for (String filename : xmlWriter.getFilesWritten()) {
filesWritten.add(nl + filename);
}
if (saveLocation != null) {
displayFiles(filesWritten, streamMapToSave.keySet().size());
}
} catch (IOException e) {
MessageBox error = new MessageBox(getSite().getShell(), SWT.ICON_ERROR | SWT.OK);
error.setMessage("Error during save operation. Files were not saved");
error.open();
}
}
private void displayFiles(@NonNull List<String> filesWritten, int numStreams) {
final int style;
if (filesWritten.isEmpty()) {
style = SWT.OK | SWT.ICON_WARNING;
} else {
style = SWT.OK | SWT.ICON_INFORMATION;
}
MessageBox confirmation = new MessageBox(getSite().getShell(), style);
StringBuilder sb = new StringBuilder(256);
sb.append(filesWritten.size()).append(" files saved for ").append(numStreams).append(" SRI streams: \n");
for (String filename : filesWritten) {
sb.append(filename);
}
confirmation.setMessage(sb.toString());
confirmation.open();
}
};
this.saveSriToFile.setEnabled(true);
final ImageDescriptor saveSriImageDescriptor = AbstractUIPlugin.imageDescriptorFromPlugin(BulkIOUIActivator.PLUGIN_ID, "icons/sri_save.gif");
this.saveSriToFile.setImageDescriptor(saveSriImageDescriptor);
//Action to clear an Active SRI (the one visible in the view) if it has been terminated)
this.clearTerminatedAction = new Action() {
@Override
public void run() {
streamMap = sriReceiver.getStreamMap();
String activeSriID = sriReceiver.getActiveStreamID();
SriWrapper stream = streamMap.get(activeSriID);
if (stream != null) {
if (stream.isEOS()) {
//If EOS is reached for the active (visible) SRI, then remove it from the Map
streamMap.remove(activeSriID);
}
if (streamMap.isEmpty()) {
//If this was the only SRI being tracked, clear the view
sriReceiver.setActiveStreamID("");
} else {
//Otherwise, switch the view to the next SRI in the Map
Map.Entry<String, SriWrapper> nextStream = streamMap.entrySet().iterator().next();
sriReceiver.setActiveStreamID(nextStream.getKey());
}
}
setTerminatedStreams(false);
}
};
this.clearTerminatedAction.setToolTipText("Clear Selected SRI");
final ImageDescriptor clearTerminatedImageDescriptor = AbstractUIPlugin.imageDescriptorFromPlugin(BulkIOUIActivator.PLUGIN_ID, "icons/sri_rem.gif");
this.clearTerminatedAction.setImageDescriptor(clearTerminatedImageDescriptor);
//Action to clear all terminated SRIs from the view
this.clearAllTerminatedAction = new Action() {
@Override
public void run() {
streamMap = sriReceiver.getStreamMap();
for (Iterator<Entry<String, SriWrapper>> i = streamMap.entrySet().iterator(); i.hasNext();) {
Entry<String, SriWrapper> stream = i.next();
if (stream.getValue().isEOS()) {
i.remove();
}
}
if (streamMap.isEmpty()) {
//If there are no non-terminated SRIs, clear the view
sriReceiver.setActiveStreamID("");
} else {
//Otherwise, switch the view to the next SRI in the Map
Map.Entry<String, SriWrapper> nextStream = streamMap.entrySet().iterator().next();
sriReceiver.setActiveStreamID(nextStream.getKey());
}
setTerminatedStreams(false);
}
};
this.clearAllTerminatedAction.setToolTipText("Clear All SRIs");
final ImageDescriptor clearAllTerminatedImageDescriptor = AbstractUIPlugin.imageDescriptorFromPlugin(BulkIOUIActivator.PLUGIN_ID,
"icons/sri_remall.gif");
this.clearAllTerminatedAction.setImageDescriptor(clearAllTerminatedImageDescriptor);
}
private class SwitchStreamMenuAction extends Action implements IMenuCreator {
private Menu menu;
private List<Action> changeStreamActions = new ArrayList<Action>();
public SwitchStreamMenuAction() {
super("Change Active Stream", IAction.AS_DROP_DOWN_MENU);
setMenuCreator(this);
}
@Override
public void run() {
}
@Override
public void dispose() {
if (menu != null) {
menu.dispose();
menu = null;
}
}
@Override
public Menu getMenu(Control parent) {
if (menu != null) {
menu.dispose();
}
menu = new Menu(parent.getShell(), SWT.POP_UP | SWT.NONE);
changeStreamActions = getStreamActions();
if (!changeStreamActions.isEmpty()) {
for (Action action : changeStreamActions) {
addActionToMenu(action);
}
}
return menu;
}
@Override
public Menu getMenu(Menu parent) {
return null;
}
public void addActionToMenu(@NonNull Action action) {
ActionContributionItem item = new ActionContributionItem(action);
item.fill(menu, -1);
}
}
@NonNull
private List<Action> getStreamActions() {
if (sriReceiver != null) {
List<Action> streamActions = new ArrayList<Action>();
streamMap = sriReceiver.getStreamMap();
for (final Map.Entry<String, SriWrapper> e : streamMap.entrySet()) {
Action action = new Action(e.getKey(), IAction.AS_RADIO_BUTTON) {
@Override
public void run() {
sriReceiver.setActiveStreamID(e.getKey()); //informs receiver of active SRI
contentProvider.setActiveSriID(e.getKey()); //informs content provider of active SRI
}
};
action.setEnabled(true);
//Use icon to denote active stream in dropdown menu
if (sriReceiver.getActiveStreamID().equals(e.getKey())) {
action.setChecked(true);
action.setText(e.getKey());
} else {
action.setText(e.getKey());
}
//add <EOS> to any streams that have reached End of Stream
if (e.getValue().isEOS()) {
action.setText("<EOS> " + e.getKey());
}
action.setToolTipText("View SRI Data for " + e.getKey());
streamActions.add(action);
}
return streamActions;
} else {
//If the receiver has not been activated yet, simply return an empty list
return new ArrayList<Action>();
}
}
public void contentChanged() {
createActions();
createToolBars();
IWorkbenchPart part = getSite().getPart();
IWorkbenchSiteProgressService service = (IWorkbenchSiteProgressService) part.getSite().getAdapter(IWorkbenchSiteProgressService.class);
if (notifyOnChanged) {
service.warnOfContentChange();
}
}
public void activateReceiver(@NonNull ScaUsesPort port, @NonNull String connectionId) {
if (sriReceiver != null || !BulkIOType.isTypeSupported(port.getRepid())) {
return;
}
BulkIOType type = BulkIOType.getType(port.getRepid());
sriReceiver = new SriDataViewReceiver(type, viewer, this);
sriReceiver.setPort(port);
sriReceiver.setConnectionID(connectionId);
try {
sriReceiver.connect();
port.eAdapters().add(SriDataView.this.portListener);
} catch (CoreException e) {
StatusManager.getManager().handle(new Status(Status.ERROR, BulkIOUIActivator.PLUGIN_ID, "Could not connect to port", e));
}
}
public void activateReceiver(@NonNull ScaUsesPort port) {
activateReceiver(port, null);
}
@Override
public void dispose() {
if (sriReceiver != null) {
sriReceiver.disconnect();
sriReceiver = null;
}
super.dispose();
}
@Override
public void setFocus() {
if (this.viewer != null) {
this.viewer.getControl().setFocus();
}
}
@Override
public void setPartName(@Nullable String partName) {
super.setPartName(partName);
}
@Override
public void setTitleToolTip(@Nullable String toolTip) {
super.setTitleToolTip(toolTip);
}
public boolean isPaused() {
return paused;
}
public TreeViewer getTreeViewer() {
return viewer;
}
public void setTerminatedStreams(boolean flag) {
terminatedStreams = flag;
}
@NonNull
public static String createSecondaryId(@NonNull ScaUsesPort port) {
EObject eObj = port.eContainer();
StringBuilder retVal = new StringBuilder();
if (eObj instanceof ScaComponent) {
ScaComponent component = (ScaComponent) eObj;
retVal.append(component.getIdentifier());
} else if (eObj instanceof ScaWaveform) {
ScaWaveform waveform = (ScaWaveform) eObj;
retVal.append(waveform.getIdentifier());
} else {
retVal.append("port");
}
retVal.append("_" + port.getName());
return retVal.toString().replace(':', '_');
}
}