/**
* 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.frontend.ui.internal;
import gov.redhawk.frontend.FrontendPackage;
import gov.redhawk.frontend.ListenerAllocation;
import gov.redhawk.frontend.TunerStatus;
import gov.redhawk.frontend.ui.FrontEndUIActivator;
import gov.redhawk.frontend.ui.TunerStatusUtil;
import gov.redhawk.internal.ui.port.nxmplot.handlers.PlotPortHandler;
import gov.redhawk.model.sca.ScaDevice;
import gov.redhawk.model.sca.ScaDomainManagerRegistry;
import gov.redhawk.model.sca.ScaPort;
import gov.redhawk.model.sca.ScaUsesPort;
import gov.redhawk.model.sca.commands.ScaModelCommand;
import gov.redhawk.model.sca.provider.ScaItemProviderAdapterFactory;
import gov.redhawk.sca.ui.ConnectPortWizard;
import gov.redhawk.ui.port.nxmplot.IPlotView;
import gov.redhawk.ui.port.nxmplot.PlotActivator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import mil.jpeojtrs.sca.util.ScaEcoreUtils;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.Command;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.IHandler;
import org.eclipse.core.expressions.EvaluationContext;
import org.eclipse.core.expressions.IEvaluationContext;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.common.notify.impl.AdapterImpl;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.edit.provider.IItemLabelProvider;
import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.ui.ISources;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.commands.ICommandService;
import org.eclipse.ui.dialogs.ListSelectionDialog;
import org.eclipse.ui.handlers.HandlerUtil;
import org.eclipse.ui.progress.UIJob;
import org.eclipse.ui.statushandlers.StatusManager;
import CF.DataType;
public class FeiPlotHandler extends AbstractHandler implements IHandler {
private static final AtomicInteger SECONDARY_ID = new AtomicInteger();
private IEvaluationContext context;
/*
* (non-Javadoc)
*
* @see org.eclipse.core.commands.IHandler#execute(org.eclipse.core.commands.ExecutionEvent)
*/
@Override
public Object execute(final ExecutionEvent event) throws ExecutionException {
// need to grab Port selections first, otherwise Plot Wizard option below will change the selection
IStructuredSelection selection = (IStructuredSelection) HandlerUtil.getActiveMenuSelection(event);
if (selection == null) {
selection = (IStructuredSelection) HandlerUtil.getCurrentSelection(event);
if (selection == null) {
return null;
}
}
final List< ? > elements = selection.toList();
String listenerAllocationID = "Plot_" + ConnectPortWizard.generateDefaultConnectionID();
for (Object obj : elements) {
if (obj instanceof TunerStatus) {
final TunerStatus tuner = (TunerStatus) obj;
final ScaDevice< ? > device = ScaEcoreUtils.getEContainerOfType(tuner, ScaDevice.class);
List<ScaPort< ? , ? >> devicePorts = device.getPorts();
final List<ScaUsesPort> usesPorts = new ArrayList<ScaUsesPort>();
for (ScaPort< ? , ? > port : devicePorts) {
if (port instanceof ScaUsesPort && PlotPortHandler.isBulkIOPortSupported(port.getRepid())) {
usesPorts.add((ScaUsesPort) port);
}
}
if (usesPorts.isEmpty()) {
Status status = new Status(IStatus.ERROR, FrontEndUIActivator.PLUGIN_ID, "No valid BulkIO output ports available, can not plot from "
+ tuner.getTunerID(), new Exception().fillInStackTrace());
StatusManager.getManager().handle(status, StatusManager.LOG | StatusManager.SHOW);
continue;
}
final DataType[] props = TunerStatusUtil.createAllocationProperties(listenerAllocationID, tuner);
final UIJob uiJob = new UIJob("Launching Plot View...") {
@Override
public IStatus runInUIThread(IProgressMonitor monitor) {
try {
IStatus retVal = createPlotView(event, props, device, tuner, usesPorts);
if (!retVal.isOK()) {
TunerStatusUtil.createDeallocationJob(tuner, props).schedule();
}
return retVal;
} catch (ExecutionException e) {
TunerStatusUtil.createDeallocationJob(tuner, props).schedule();
return new Status(IStatus.ERROR, FrontEndUIActivator.PLUGIN_ID, "Failed to open plot view", e);
}
}
};
Job allocJob = TunerStatusUtil.createAllocationJob(tuner, props);
allocJob.addJobChangeListener(new JobChangeAdapter() {
@Override
public void done(IJobChangeEvent event) {
if (event.getResult().isOK()) {
uiJob.setUser(false);
uiJob.setSystem(true);
uiJob.schedule();
}
}
});
allocJob.setUser(true);
allocJob.schedule();
}
}
return null;
}
private IStatus createPlotView(final ExecutionEvent event, final DataType[] props, final ScaDevice< ? > device, final TunerStatus tuner,
final List<ScaUsesPort> usesPorts) throws ExecutionException {
IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindowChecked(event);
String plotType = event.getParameter(IPlotView.PARAM_PLOT_TYPE);
String isFft = event.getParameter(IPlotView.PARAM_ISFFT);
final ScaItemProviderAdapterFactory factory = new ScaItemProviderAdapterFactory();
if (usesPorts.size() > 1) {
ListSelectionDialog dialog = new ListSelectionDialog(HandlerUtil.getActiveShellChecked(event), usesPorts, new ArrayContentProvider(),
new AdapterFactoryLabelProvider(factory), "Select output port to use:");
dialog.setTitle("Ambiguous Data Port");
if (dialog.open() == Window.OK) {
Object[] result = dialog.getResult();
if (result.length >= 1) {
usesPorts.retainAll(Arrays.asList(result));
} else {
return Status.CANCEL_STATUS;
}
} else {
return Status.CANCEL_STATUS;
}
} else if (usesPorts.isEmpty()) {
return new Status(IStatus.ERROR, FrontEndUIActivator.PLUGIN_ID, "Failed to find port to plot.");
}
EvaluationContext exContext = new EvaluationContext(context, usesPorts);
exContext.addVariable(ISources.ACTIVE_WORKBENCH_WINDOW_NAME, window);
Map<String, Object> exParam = new HashMap<String, Object>();
exParam.put(IPlotView.PARAM_PLOT_TYPE, plotType);
exParam.put(IPlotView.PARAM_ISFFT, isFft);
final String listenerID = TunerStatusUtil.getListenerID(props);
exParam.put(IPlotView.PARAM_CONNECTION_ID, listenerID);
exParam.put(IPlotView.PARAM_SECONDARY_ID, createSecondaryId());
ICommandService svc = (ICommandService) window.getService(ICommandService.class);
Command comm = svc.getCommand(IPlotView.COMMAND_ID);
ExecutionEvent ex = new ExecutionEvent(comm, exParam, null, exContext);
exContext.addVariable(ISources.ACTIVE_CURRENT_SELECTION_NAME, new StructuredSelection(usesPorts));
exContext.addVariable(ISources.ACTIVE_MENU_SELECTION_NAME, new StructuredSelection(usesPorts));
final StringBuilder name = new StringBuilder();
final StringBuilder tooltip = new StringBuilder();
createTooltip(factory, name, tooltip, usesPorts);
factory.dispose();
final IPlotView view = PlotActivator.getDefault().showPlotView(ex);
if (view != null) {
view.setPartName(name.toString());
view.setTitleToolTip(tooltip.toString());
view.getPlotPageBook().addDisposeListener(getDisposeListener(tuner, props, device));
ScaModelCommand.execute(tuner, new ScaModelCommand() {
@Override
public void execute() {
for (ListenerAllocation a : tuner.getListenerAllocations()) {
if (a.getListenerID().equals(listenerID)) {
a.eAdapters().add(new AdapterImpl() {
@Override
public void notifyChanged(org.eclipse.emf.common.notify.Notification msg) {
if (msg.isTouch()) {
return;
}
switch (msg.getFeatureID(ListenerAllocation.class)) {
case FrontendPackage.LISTENER_ALLOCATION__TUNER_STATUS:
if (msg.getNewValue() == null) {
((Notifier) msg.getNotifier()).eAdapters().remove(this);
if (view.getPlotPageBook().isDisposed()) {
return;
}
view.getPlotPageBook().getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
view.getPlotPageBook().dispose();
}
});
}
break;
default:
}
}
});
}
}
}
});
} else {
return Status.CANCEL_STATUS;
}
return Status.OK_STATUS;
}
@Override
public void setEnabled(Object evaluationContext) {
if (evaluationContext instanceof IEvaluationContext) {
this.context = (IEvaluationContext) evaluationContext;
}
super.setEnabled(evaluationContext);
}
/**
* Calls deallocateCapacity(DataType[] capacities) when the plot view is disposed
* @param props Listener Capacity to pass to deallocateCapacity()
* @return
*/
private DisposeListener getDisposeListener(final TunerStatus tuner, final DataType[] props, final ScaDevice< ? > device) {
DisposeListener disposeListener = new DisposeListener() {
@Override
public void widgetDisposed(DisposeEvent e) {
if (TunerStatusUtil.containsListener(tuner, props)) {
TunerStatusUtil.createDeallocationJob(tuner, props).schedule();
}
}
};
return disposeListener;
}
private String createSecondaryId() {
return "FEI" + FeiPlotHandler.SECONDARY_ID.incrementAndGet();
}
private void createTooltip(final ScaItemProviderAdapterFactory factory, final StringBuilder name, final StringBuilder tooltip, List<ScaUsesPort> usesPorts) {
List<String> tmpList4Tooltip = new LinkedList<String>();
int loopCount = 0;
for (ScaUsesPort usesPort : usesPorts) {
loopCount++;
if (loopCount >= 2) {
tmpList4Tooltip.add(0, "\n");
}
for (EObject eObj = usesPort; !(eObj instanceof ScaDomainManagerRegistry) && eObj != null; eObj = eObj.eContainer()) {
Adapter adapter = factory.adapt(eObj, IItemLabelProvider.class);
if (adapter instanceof IItemLabelProvider) {
IItemLabelProvider lp = (IItemLabelProvider) adapter;
String text = lp.getText(eObj);
if (text != null && !text.isEmpty()) {
tmpList4Tooltip.add(0, text);
}
}
}
String nameStr = usesPort.getName();
if (nameStr != null && !nameStr.isEmpty()) {
name.append(nameStr).append(" ");
}
}
String delim = "";
if (!tmpList4Tooltip.isEmpty()) {
tooltip.append(delim);
delim = "\n";
for (Iterator<String> i = tmpList4Tooltip.iterator(); i.hasNext();) {
String s = i.next();
tooltip.append(s);
if (i.hasNext() && !("\n").equals(s)) {
tooltip.append(" -> ");
}
}
}
}
}