/*******************************************************************************
* Copyright (c) 2004 Vlad Dumitrescu and others.
* 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
*
* Contributors:
* Vlad Dumitrescu
*******************************************************************************/
package org.erlide.ui.views.processlist;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.xtext.xbase.lib.Procedures.Procedure1;
import org.erlide.backend.BackendCore;
import org.erlide.backend.api.IBackend;
import org.erlide.engine.ErlangEngine;
import org.erlide.runtime.api.IOtpRpc;
import org.erlide.runtime.events.ErlEvent;
import org.erlide.runtime.events.ErlangEventHandler;
import org.erlide.ui.util.DisplayUtils;
import org.erlide.ui.views.BackendContentProvider;
import org.erlide.ui.views.BackendLabelProvider;
import com.ericsson.otp.erlang.OtpErlangList;
import com.ericsson.otp.erlang.OtpErlangObject;
import com.ericsson.otp.erlang.OtpErlangPid;
import com.ericsson.otp.erlang.OtpErlangString;
import com.ericsson.otp.erlang.OtpErlangTuple;
import com.google.common.eventbus.Subscribe;
/**
*
*
*
* @author Vlad Dumitrescu
*/
public class ProcessListView extends ViewPart {
public static final String ID = "org.erlide.ui.views.processlist.ProcessListView";
private ComboViewer backends;
TableViewer viewer;
private Action refreshAction;
Action doubleClickAction;
/*
* The content provider class is responsible for providing objects to the
* view. It can wrap existing objects in adapters or simply return objects
* as-is. These objects may be sensitive to the current input of the view,
* or ignore it and always show the same content (like Task List, for
* example).
*/
class ViewContentProvider implements IStructuredContentProvider {
private final ProcessEventHandler handler = new ProcessEventHandler(getBackend()
.getName());
public ViewContentProvider() {
getBackend().getNodeProxy().registerEventListener(handler);
}
@Override
public void inputChanged(final Viewer v, final Object oldInput,
final Object newInput) {
}
@Override
public void dispose() {
}
@Override
public Object[] getElements(final Object parent) {
final IOtpRpc backend = getBackend().getOtpRpc();
if (backend == null) {
return new OtpErlangObject[] {};
}
final OtpErlangList r = ErlangEngine.getInstance().getProclistService()
.getProcessList(backend);
if (r == null || r.arity() == 0) {
return new OtpErlangObject[] {};
}
final OtpErlangObject[] ss = new OtpErlangObject[r.elements().length];
for (int i = 0; i < r.elements().length; i++) {
final OtpErlangTuple e = (OtpErlangTuple) r.elementAt(i);
ss[i] = e;
}
return ss;
}
class ProcessEventHandler extends ErlangEventHandler {
public ProcessEventHandler(final String backendName) {
super("processlist", backendName);
}
@Subscribe
public void handleEvent(final ErlEvent event) {
if (!event.getTopic().equals(getTopic())) {
return;
}
DisplayUtils.asyncExec(new Runnable() {
@Override
public void run() {
if (!viewer.getControl().isDisposed()) {
viewer.refresh();
}
}
});
}
}
}
static class ViewLabelProvider extends LabelProvider implements ITableLabelProvider {
@Override
public String getColumnText(final Object obj, final int index) {
final OtpErlangTuple t = (OtpErlangTuple) obj;
final OtpErlangObject e = t.elementAt(index + 1);
if (e instanceof OtpErlangString) {
return ((OtpErlangString) e).stringValue();
}
return e.toString();
}
@Override
public Image getColumnImage(final Object obj, final int index) {
if (index == 0) {
return getImage(obj);
}
return null;
}
@Override
public Image getImage(final Object obj) {
return PlatformUI.getWorkbench().getSharedImages()
.getImage(ISharedImages.IMG_OBJ_ELEMENT);
}
}
/**
* The constructor.
*/
public ProcessListView() {
}
/**
* This is a callback that will allow us to create the viewer and initialize
* it.
*/
@Override
public void createPartControl(final Composite parent) {
final Composite container = new Composite(parent, SWT.NONE);
final GridLayout thisLayout = new GridLayout(2, false);
container.setLayout(thisLayout);
thisLayout.marginWidth = 5;
thisLayout.marginHeight = 5;
thisLayout.makeColumnsEqualWidth = false;
thisLayout.verticalSpacing = 1;
final Label label = new Label(container, SWT.SHADOW_NONE);
label.setText("Erlang backend node");
backends = new ComboViewer(container, SWT.SINGLE | SWT.V_SCROLL);
final Combo combo = backends.getCombo();
combo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
backends.getControl().setSize(new org.eclipse.swt.graphics.Point(319, 18));
backends.setContentProvider(new BackendContentProvider());
backends.setLabelProvider(new BackendLabelProvider());
backends.setInput(BackendCore.getBackendManager());
viewer = new TableViewer(container, SWT.SINGLE | SWT.V_SCROLL
| SWT.FULL_SELECTION);
final Table table = viewer.getTable();
final GridData layoutData = new GridData(SWT.FILL, SWT.FILL, false, true, 2, 1);
table.setLayoutData(layoutData);
final Table t = (Table) viewer.getControl();
final TableColumn colPid = new TableColumn(t, SWT.LEAD);
colPid.setText("Pid/Name");
colPid.setWidth(150);
final TableColumn colStart = new TableColumn(t, SWT.LEAD);
colStart.setText("Initial call");
colStart.setWidth(300);
final TableColumn colReds = new TableColumn(t, SWT.LEAD);
colReds.setText("Reds");
colReds.setWidth(80);
final TableColumn colMsgs = new TableColumn(t, SWT.LEAD);
colMsgs.setText("Msgs");
colMsgs.setWidth(60);
viewer.setContentProvider(new ViewContentProvider());
viewer.setLabelProvider(new ViewLabelProvider());
// viewer.setSorter(new NameSorter());
viewer.setInput(getViewSite());
viewer.addDoubleClickListener(new IDoubleClickListener() {
@Override
public void doubleClick(final DoubleClickEvent event) {
doubleClickAction.run();
}
});
t.setLinesVisible(true);
t.setHeaderVisible(true);
initErlangService();
makeActions();
hookContextMenu();
hookDoubleClickAction();
contributeToActionBars();
}
private void initErlangService() {
// TODO this is wrong - all backends should be inited
BackendCore.getBackendManager().forEachBackend(new Procedure1<IBackend>() {
@Override
public void apply(final IBackend b) {
ErlangEngine.getInstance().getProclistService()
.processListInit(b.getOtpRpc());
}
});
}
private void hookContextMenu() {
final MenuManager menuMgr = new MenuManager("#PopupMenu");
final Menu menu = menuMgr.createContextMenu(viewer.getControl());
viewer.getControl().setMenu(menu);
getSite().registerContextMenu(menuMgr, viewer);
menuMgr.setRemoveAllWhenShown(true);
menuMgr.addMenuListener(new IMenuListener() {
@Override
public void menuAboutToShow(final IMenuManager manager) {
ProcessListView.this.fillContextMenu(manager);
}
});
}
private void contributeToActionBars() {
final IActionBars bars = getViewSite().getActionBars();
fillLocalPullDown(bars.getMenuManager());
fillLocalToolBar(bars.getToolBarManager());
}
private void fillLocalPullDown(final IMenuManager manager) {
manager.add(refreshAction);
manager.add(new Separator());
}
void fillContextMenu(final IMenuManager manager) {
manager.add(refreshAction);
// Other plug-ins can contribute there actions here
manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
}
private void fillLocalToolBar(final IToolBarManager manager) {
manager.add(refreshAction);
}
private void makeActions() {
refreshAction = new Action() {
@Override
public void run() {
viewer.refresh();
}
};
refreshAction.setText("Refresh");
refreshAction.setToolTipText("Refresh process list");
refreshAction.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages()
.getImageDescriptor(ISharedImages.IMG_OBJS_INFO_TSK));
doubleClickAction = new Action() {
@Override
public void run() {
final ISelection selection = viewer.getSelection();
final Object obj = ((IStructuredSelection) selection).getFirstElement();
if (obj == null) {
return;
}
final OtpErlangPid pid = (OtpErlangPid) ((OtpErlangTuple) obj)
.elementAt(0);
final OtpErlangObject r = ErlangEngine.getInstance().getProclistService()
.getProcessInfo(getBackend().getOtpRpc(), pid);
if (r instanceof OtpErlangList) {
final OtpErlangList l = (OtpErlangList) r;
final StringBuilder s = new StringBuilder();
for (int i = 0; i < l.arity(); i++) {
final OtpErlangTuple e = (OtpErlangTuple) l.elementAt(i);
s.append(' ').append(e.elementAt(0).toString()).append("\t= ")
.append(e.elementAt(1).toString()).append('\n');
}
showMessage(s.toString());
} else {
showMessage("Process " + pid.toString()
+ " is probably dead.\nPlease refresh process list.");
}
}
};
}
private void hookDoubleClickAction() {
}
void showMessage(final String message) {
MessageDialog.openInformation(viewer.getControl().getShell(),
"Process list view", message);
}
/**
* Passing the focus request to the viewer's control.
*/
@Override
public void setFocus() {
viewer.getControl().setFocus();
}
public IBackend getBackend() {
final IStructuredSelection sel = (IStructuredSelection) backends.getSelection();
if (sel.getFirstElement() != null) {
final IBackend b = (IBackend) sel.getFirstElement();
return b;
}
return BackendCore.getBackendManager().getIdeBackend();
}
}