blob: 3f43d4b97f752be698258c348981e98ef75c3c7c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008 IBM Corporation.
* 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:
* IBM Corporation - Initial API and implementation
*******************************************************************************/
package org.eclipse.ptp.ui.views;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.layout.PixelConverter;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITreeSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.ptp.core.IModelManager;
import org.eclipse.ptp.core.PTPCorePlugin;
import org.eclipse.ptp.core.attributes.IAttribute;
import org.eclipse.ptp.core.attributes.IAttributeDefinition;
import org.eclipse.ptp.core.elements.IPJob;
import org.eclipse.ptp.core.elements.IPQueue;
import org.eclipse.ptp.core.elements.IResourceManager;
import org.eclipse.ptp.core.elements.attributes.ElementAttributes;
import org.eclipse.ptp.core.elements.attributes.JobAttributes;
import org.eclipse.ptp.core.elements.events.IChangedJobEvent;
import org.eclipse.ptp.core.elements.events.IChangedMachineEvent;
import org.eclipse.ptp.core.elements.events.IChangedQueueEvent;
import org.eclipse.ptp.core.elements.events.INewJobEvent;
import org.eclipse.ptp.core.elements.events.INewMachineEvent;
import org.eclipse.ptp.core.elements.events.INewQueueEvent;
import org.eclipse.ptp.core.elements.events.IRemoveJobEvent;
import org.eclipse.ptp.core.elements.events.IRemoveMachineEvent;
import org.eclipse.ptp.core.elements.events.IRemoveQueueEvent;
import org.eclipse.ptp.core.elements.listeners.IQueueChildListener;
import org.eclipse.ptp.core.elements.listeners.IResourceManagerChildListener;
import org.eclipse.ptp.core.events.IChangedResourceManagerEvent;
import org.eclipse.ptp.core.events.INewResourceManagerEvent;
import org.eclipse.ptp.core.events.IRemoveResourceManagerEvent;
import org.eclipse.ptp.core.listeners.IModelManagerChildListener;
import org.eclipse.ptp.internal.ui.actions.TerminateJobFromListAction;
import org.eclipse.ptp.ui.IPTPUIConstants;
import org.eclipse.ptp.ui.IRMSelectionListener;
import org.eclipse.ptp.ui.PTPUIPlugin;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.ui.model.IWorkbenchAdapter;
import org.eclipse.ui.part.ViewPart;
public class JobsListView extends ViewPart {
private final class MMChildListener implements IModelManagerChildListener {
/* (non-Javadoc)
* @see org.eclipse.ptp.core.listeners.IModelManagerChildListener#handleEvent(org.eclipse.ptp.core.events.IChangedResourceManagerEvent)
*/
public void handleEvent(IChangedResourceManagerEvent e) {
// Don't need to do anything
}
/* (non-Javadoc)
* @see org.eclipse.ptp.core.listeners.IModelManagerChildListener#handleEvent(org.eclipse.ptp.core.events.INewResourceManagerEvent)
*/
public void handleEvent(INewResourceManagerEvent e) {
/*
* Add resource manager child listener so we get notified when new
* machines are added to the model.
*/
final IResourceManager rm = e.getResourceManager();
rm.addChildListener(resourceManagerListener);
}
/* (non-Javadoc)
* @see org.eclipse.ptp.core.listeners.IModelManagerChildListener#handleEvent(org.eclipse.ptp.core.events.IRemoveResourceManagerEvent)
*/
// Update the button here.
public void handleEvent(IRemoveResourceManagerEvent e) {
/*
* Removed resource manager child listener when resource manager is removed.
*/
e.getResourceManager().removeChildListener(resourceManagerListener);
}
}
private final class QueueChildListener implements IQueueChildListener {
/* (non-Javadoc)
* @see org.eclipse.ptp.core.elements.listeners.IQueueChildListener#handleEvent(org.eclipse.ptp.core.elements.events.IChangedJobEvent)
*/
public void handleEvent(IChangedJobEvent e) {
update(e.getJobs().toArray(new IPJob[0]));
// Refresh the terminate job button
// TODO: scalability bottleneck
PTPUIPlugin.getDisplay().syncExec(new Runnable() {
public void run() {
terminateAllAction.updateTerminateJobState();
}
});
}
/* (non-Javadoc)
* @see org.eclipse.ptp.core.elements.listeners.IQueueChildListener#handleEvent(org.eclipse.ptp.core.elements.events.INewJobEvent)
*/
public void handleEvent(final INewJobEvent e) {
if (fColumnsNeedUpdating) {
PTPUIPlugin.getDisplay().syncExec(new Runnable() {
public void run() {
addColumns(viewer, e.getJobs().iterator().next());
}
});
}
refresh();
}
/* (non-Javadoc)
* @see org.eclipse.ptp.core.elements.listeners.IQueueChildListener#handleEvent(org.eclipse.ptp.core.elements.events.IRemoveJobEvent)
*/
public void handleEvent(IRemoveJobEvent e) {
refresh();
}
}
private final class RMChildListener implements IResourceManagerChildListener {
/* (non-Javadoc)
* @see org.eclipse.ptp.core.elements.listeners.IResourceManagerMachineListener#handleEvent(org.eclipse.ptp.core.elements.events.IResourceManagerChangedMachineEvent)
*/
public void handleEvent(IChangedMachineEvent e) {
// Don't need to do anything
}
/* (non-Javadoc)
* @see org.eclipse.ptp.core.elements.listeners.IResourceManagerChildListener#handleEvent(org.eclipse.ptp.core.elements.events.IResourceManagerChangedQueueEvent)
*/
public void handleEvent(IChangedQueueEvent e) {
// Can safely ignore
}
/* (non-Javadoc)
* @see org.eclipse.ptp.core.elements.listeners.IResourceManagerMachineListener#handleEvent(org.eclipse.ptp.core.elements.events.IResourceManagerNewMachineEvent)
*/
public void handleEvent(INewMachineEvent e) {
}
/* (non-Javadoc)
* @see org.eclipse.ptp.core.elements.listeners.IResourceManagerChildListener#handleEvent(org.eclipse.ptp.core.elements.events.INewQueueEvent)
*/
public void handleEvent(INewQueueEvent e) {
for (IPQueue queue : e.getQueues()) {
queue.addChildListener(queueChildListener);
}
}
/* (non-Javadoc)
* @see org.eclipse.ptp.core.elements.listeners.IResourceManagerMachineListener#handleEvent(org.eclipse.ptp.core.elements.events.IResourceManagerRemoveMachineEvent)
*/
public void handleEvent(IRemoveMachineEvent e) {
}
/* (non-Javadoc)
* @see org.eclipse.ptp.core.elements.listeners.IResourceManagerChildListener#handleEvent(org.eclipse.ptp.core.elements.events.IResourceManagerRemoveQueueEvent)
*/
public void handleEvent(IRemoveQueueEvent e) {
for (IPQueue queue : e.getQueues()) {
queue.removeChildListener(queueChildListener);
}
}
}
private TableViewer viewer;
private TerminateJobFromListAction terminateAllAction;
private IResourceManager fSelectedRM = null;
private IPQueue fSelectedQueue = null;
private boolean fColumnsNeedUpdating = false;
/*
* Model listeners
*/
private final IModelManagerChildListener modelManagerListener = new MMChildListener();
private final IResourceManagerChildListener resourceManagerListener = new RMChildListener();
private final IQueueChildListener queueChildListener = new QueueChildListener();
private final Set<IAttributeDefinition<?,?,?>> colDefs = Collections.synchronizedSet(new HashSet<IAttributeDefinition<?,?,?>>());
/* (non-Javadoc)
* @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
*/
@Override
public void createPartControl(Composite parent) {
parent.setLayout(new FillLayout());
viewer = new TableViewer(parent, SWT.H_SCROLL
| SWT.V_SCROLL | SWT.MULTI | SWT.FULL_SELECTION);
viewer.getTable().setLinesVisible(true);
viewer.getTable().setHeaderVisible(true);
viewer.setUseHashlookup(true);
viewer.setContentProvider(new IStructuredContentProvider() {
public void dispose() {
}
public Object[] getElements(Object inputElement) {
/*
* Just get jobs from the queue if one is selected
*/
if (fSelectedQueue != null) {
return fSelectedQueue.getJobs();
}
/*
* Otherwise get jobs from all queues the RM knows about
*/
if (fSelectedRM != null) {
return getAllJobs(fSelectedRM).toArray(new IPJob[0]);
}
/*
* Otherwise get all jobs from all queues
* TODO: should probably not do this!
*/
Set<IPJob> jobs = new HashSet<IPJob>();
for (IResourceManager rm : PTPCorePlugin.getDefault().getModelManager().getUniverse().getResourceManagers()) {
jobs.addAll(getAllJobs(rm));
}
return jobs.toArray(new IPJob[0]);
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
});
viewer.setSorter(new ViewerSorter() {
public int compare(Viewer viewer, Object j1, Object j2) {
return ((IPJob)j1).getName().compareTo(((IPJob)j2).getName());
}
});
createColumns(viewer);
getSite().setSelectionProvider(viewer);
// Use view toolbar
IToolBarManager toolBarMgr = getViewSite().getActionBars().getToolBarManager();
terminateAllAction = new TerminateJobFromListAction(this);
toolBarMgr.add(new Separator(IPTPUIConstants.IUIACTIONGROUP));
toolBarMgr.appendToGroup(IPTPUIConstants.IUIACTIONGROUP, terminateAllAction);
/*terminateAllAction = new TerminateJobAction(viewer);
toolBarMgr.appendToGroup(IPTPUIConstants.IUIACTIONGROUP, terminateAllAction);*/
IModelManager mm = PTPCorePlugin.getDefault().getModelManager();
viewer.setInput(mm.getUniverse());
/*
* Add us to any existing RM's. I guess it's possible we could
* miss a RM if a new event arrives while we're doing this, but is
* it a problem?
*/
for (IResourceManager rm : mm.getUniverse().getResourceManagers()) {
rm.addChildListener(resourceManagerListener);
for (IPQueue queue : rm.getQueues()) {
queue.addChildListener(queueChildListener);
}
}
mm.addListener(modelManagerListener);
/*
* Link this view to the ResourceManagerView
*/
PTPUIPlugin.getDefault().getRMManager().addRMSelectionListener(new IRMSelectionListener() {
public void selectionChanged(ISelection selection) {
IResourceManager oldRM = fSelectedRM;
fSelectedQueue = null;
if (selection.isEmpty()) {
fSelectedRM = null;
} else {
TreePath path = ((ITreeSelection)selection).getPaths()[0];
fSelectedRM = (IResourceManager)path.getFirstSegment();
if (path.getLastSegment() instanceof IPQueue) {
fSelectedQueue = (IPQueue)path.getLastSegment();
}
}
if (oldRM != fSelectedRM) {
createColumns(viewer);
}
refresh();
}
public void setDefault(IResourceManager rm) {
// Ignore
}
});
}
public TableViewer getViewer() {
return viewer;
}
/* (non-Javadoc)
* @see org.eclipse.ui.part.WorkbenchPart#setFocus()
*/
@Override
public void setFocus() {
}
/**
* @param tableViewer
* @param fontMetrics
* @param attrDef
*/
private void addColumn(final IAttributeDefinition<?, ?, ?> attrDef, boolean resizable) {
TableViewerColumn column = new TableViewerColumn(viewer, SWT.NONE);
column.setLabelProvider(new ColumnLabelProvider(){
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ColumnLabelProvider#getImage(java.lang.Object)
*/
@Override
public Image getImage(Object element) {
/*
* If this is the state column, get the image, otherwise return
* null and just use the text.
*/
if (attrDef == JobAttributes.getStateAttributeDefinition()) {
IWorkbenchAdapter adapter = (IWorkbenchAdapter)Platform.getAdapterManager().getAdapter(element, IWorkbenchAdapter.class);
if (adapter != null) {
return adapter.getImageDescriptor(element).createImage();
}
}
return null;
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ColumnLabelProvider#getText(java.lang.Object)
*/
@Override
public String getText(Object element) {
/*
* If this is not the state column, then use the attribute text.
* If it is the state column, just return null an use the icon.
*/
IPJob job = (IPJob)element;
if (attrDef != JobAttributes.getStateAttributeDefinition()) {
IAttribute<?,?,?> attr = job.getAttribute(attrDef.getId());
if (attr != null) {
return attr.getValueAsString();
}
}
return null;
}
});
column.getColumn().setResizable(resizable);
column.getColumn().setMoveable(true);
// this will need to sort by the col
//column.getColumn().addSelectionListener(getHeaderListener());
String name = attrDef.getName();
column.getColumn().setText(name);
PixelConverter converter = new PixelConverter(viewer.getControl());
int colWidth = converter.convertWidthInCharsToPixels(resizable ? name.length() + 5 : name.length());
column.getColumn().setWidth(colWidth);
colDefs.add(attrDef);
}
/**
* @param tableViewer
* @param job
*/
private void addColumns(TableViewer tableViewer, IPJob job) {
if (job != null) {
for (IAttribute<?,?,?> attr : job.getAttributes()) {
IAttributeDefinition<?,?,?> attrDef = attr.getDefinition();
if (!colDefs.contains(attrDef) && attrDef.getDisplay()) {
addColumn(attrDef, true);
}
}
}
}
/**
* Create the columns for the table. This is done whenever the selection
* in the RM view changes.
*
* 1. Always create the state and name columns.
* 2. Assume that job attributes from a single RM are always constant, so only
* look at the first job from any queue.
* 3. Do this for each RM (if no RM selected)
*
* @param tableViewer
*/
private void createColumns(TableViewer tableViewer) {
for (TableColumn column : tableViewer.getTable().getColumns()) {
column.dispose();
}
colDefs.clear();
addColumn(JobAttributes.getStateAttributeDefinition(), false);
addColumn(ElementAttributes.getNameAttributeDefinition(), true);
IPJob[] jobs = getFirstJobs();
if (jobs.length > 0) {
for (IPJob job : jobs) {
addColumns(tableViewer, job);
}
fColumnsNeedUpdating = false;
} else {
fColumnsNeedUpdating = true;
}
}
/**
* Find all jobs from all queues belonging to a RM
*
* @param rm
* @return set of jobs
*/
private Set<IPJob> getAllJobs(IResourceManager rm) {
Set<IPJob> jobList = new HashSet<IPJob>();
for (IPQueue queue : rm.getQueues()) {
for (IPJob job : queue.getJobs()) {
jobList.add(job);
}
}
return jobList;
}
/**
* Finds the first few jobs to use to create the table columns
* If an RM queue is selected, just return the first job
* If an RM is selected, return the first job from one of the queues
* If no RM is selected, return the first job from one of the queues in each RM
*
* @return first job or null if there are no jobs
*/
private IPJob[] getFirstJobs() {
List<IPJob> jobsList = new ArrayList<IPJob>();
if (fSelectedQueue != null) {
IPJob job = getFirstJob(fSelectedQueue);
if (job != null) {
jobsList.add(job);
}
} else if (fSelectedRM != null) {
for (IPQueue queue : fSelectedRM.getQueues()) {
IPJob job = getFirstJob(queue);
if (job != null) {
jobsList.add(job);
break;
}
}
} else {
for (IResourceManager rm : PTPCorePlugin.getDefault().getModelManager().getUniverse().getResourceManagers()) {
for (IPQueue queue : rm.getQueues()) {
IPJob job = getFirstJob(queue);
if (job != null) {
jobsList.add(job);
break;
}
}
}
}
return jobsList.toArray(new IPJob[0]);
}
/**
* Get the first job from the queue
*
* @param queue
* @return first job in the queue or null if there are no jobs
*/
private IPJob getFirstJob(IPQueue queue) {
IPJob[] jobs = queue.getJobs();
if (jobs.length > 0) {
return jobs[0];
}
return null;
}
/**
* Refresh the viewer from the model.
*/
private void refresh() {
if (!viewer.getTable().isDisposed()) {
PTPUIPlugin.getDisplay().asyncExec(new Runnable() {
public void run() {
viewer.refresh();
}
});
}
}
/**
* Update the viewer if the supplied jobs have changed
*
* @param jobs array of jobs that have changed
*/
private void update(final IPJob[] jobs) {
if (!viewer.getTable().isDisposed()) {
PTPUIPlugin.getDisplay().asyncExec(new Runnable() {
public void run() {
viewer.update(jobs, null);
}
});
}
}
}