blob: 6e7b14005e9674e553cad974c84662be63f28821 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2009 IBM Corporation 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.ui.internal.progress;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.IconAndMessageDialog;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.WorkbenchMessages;
import org.eclipse.ui.progress.WorkbenchJob;
/**
* The BlockedJobsDialog class displays a dialog that provides information on
* the running jobs.
*/
public class BlockedJobsDialog extends IconAndMessageDialog {
/**
* The singleton dialog instance. A singleton avoids the possibility of
* recursive dialogs being created. The singleton is created when a dialog
* is requested, and cleared when the dialog is disposed.
*/
protected static BlockedJobsDialog singleton;
/**
* The running jobs progress viewer.
*/
private DetailedProgressViewer viewer;
/**
* The name of the task that is being blocked.
*/
private String blockedTaskName = ProgressMessages.SubTaskInfo_UndefinedTaskName;
/**
* The Cancel button control.
*/
private Button cancelSelected;
/**
* The cursor for the buttons.
*/
private Cursor arrowCursor;
/**
* The cursor for the Shell.
*/
private Cursor waitCursor;
private IProgressMonitor blockingMonitor;
private JobTreeElement blockedElement = new BlockedUIElement();
/**
* The BlockedUIElement is the JobTreeElement that represents the blocked
* job in the dialog.
*/
private class BlockedUIElement extends JobTreeElement {
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.internal.progress.JobTreeElement#getChildren()
*/
Object[] getChildren() {
return ProgressManagerUtil.EMPTY_OBJECT_ARRAY;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.internal.progress.JobTreeElement#getDisplayString()
*/
String getDisplayString() {
if (blockedTaskName == null || blockedTaskName.length() == 0) {
return ProgressMessages.BlockedJobsDialog_UserInterfaceTreeElement;
}
return blockedTaskName;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.internal.progress.JobTreeElement#getDisplayImage()
*/
public Image getDisplayImage() {
return JFaceResources.getImage(ProgressManager.WAITING_JOB_KEY);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.internal.progress.JobTreeElement#hasChildren()
*/
boolean hasChildren() {
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.internal.progress.JobTreeElement#isActive()
*/
boolean isActive() {
return true;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.internal.progress.JobTreeElement#isJobInfo()
*/
boolean isJobInfo() {
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.internal.progress.JobTreeElement#cancel()
*/
public void cancel() {
blockingMonitor.setCanceled(true);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.internal.progress.JobTreeElement#isCancellable()
*/
public boolean isCancellable() {
return true;
}
}
/**
* Creates a progress monitor dialog under the given shell. It also sets the
* dialog's message. The dialog is opened automatically after a reasonable
* delay. When no longer needed, the dialog must be closed by calling
* <code>close(IProgressMonitor)</code>, where the supplied monitor is
* the same monitor passed to this factory method.
*
* @param parentShell
* The parent shell, or <code>null</code> to create a top-level
* shell. If the parentShell is not null we will open immediately
* as parenting has been determined. If it is <code>null</code>
* then the dialog will not open until there is no modal shell
* blocking it.
* @param blockedMonitor
* The monitor that is currently blocked
* @param reason
* A status describing why the monitor is blocked
* @param taskName
* A name to give the blocking task in the dialog
* @return BlockedJobsDialog
*/
public static BlockedJobsDialog createBlockedDialog(Shell parentShell,
IProgressMonitor blockedMonitor, IStatus reason, String taskName) {
// use an existing dialog if available
if (singleton != null) {
return singleton;
}
singleton = new BlockedJobsDialog(parentShell, blockedMonitor, reason);
if (taskName == null || taskName.length() == 0)
singleton
.setBlockedTaskName(ProgressMessages.BlockedJobsDialog_UserInterfaceTreeElement);
else
singleton.setBlockedTaskName(taskName);
/**
* If there is no parent shell we have not been asked for a parent so we
* want to avoid blocking. If there is a parent then it is OK to open.
*/
if (parentShell == null) {
// create the job that will open the dialog after a delay.
WorkbenchJob dialogJob = new WorkbenchJob(
WorkbenchMessages.EventLoopProgressMonitor_OpenDialogJobName) {
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor)
*/
public IStatus runInUIThread(IProgressMonitor monitor) {
if (singleton == null) {
return Status.CANCEL_STATUS;
}
if (ProgressManagerUtil.rescheduleIfModalShellOpen(this)) {
return Status.CANCEL_STATUS;
}
singleton.open();
return Status.OK_STATUS;
}
};
// Wait for long operation time to prevent a proliferation
// of dialogs
dialogJob.setSystem(true);
dialogJob.schedule(PlatformUI.getWorkbench().getProgressService()
.getLongOperationTime());
} else {
singleton.open();
}
return singleton;
}
/**
* monitor is done. Clear the receiver.
*
* @param monitor
* The monitor that is now cleared.
*/
public static void clear(IProgressMonitor monitor) {
if (singleton == null) {
return;
}
singleton.close(monitor);
}
/**
* Creates a progress monitor dialog under the given shell. It also sets the
* dialog's\ message. <code>open</code> is non-blocking.
*
* @param parentShell
* The parent shell, or <code>null</code> to create a top-level
* shell.
* @param blocking
* The monitor that is blocking the job
* @param blockingStatus
* A status describing why the monitor is blocked
*/
private BlockedJobsDialog(Shell parentShell, IProgressMonitor blocking,
IStatus blockingStatus) {
super(parentShell == null ? ProgressManagerUtil.getDefaultParent()
: parentShell);
blockingMonitor = blocking;
setShellStyle(SWT.BORDER | SWT.TITLE | SWT.APPLICATION_MODAL
| SWT.RESIZE | SWT.MAX | getDefaultOrientation());
// no close button
setBlockOnOpen(false);
setMessage(blockingStatus.getMessage());
}
/**
* This method creates the dialog area under the parent composite.
*
* @param parent
* The parent Composite.
*
* @return parent The parent Composite.
*/
protected Control createDialogArea(Composite parent) {
setMessage(message);
createMessageArea(parent);
showJobDetails(parent);
return parent;
}
/**
* This method creates a dialog area in the parent composite and displays a
* progress tree viewer of the running jobs.
*
* @param parent
* The parent Composite.
*/
void showJobDetails(Composite parent) {
viewer = new DetailedProgressViewer(parent, SWT.MULTI | SWT.H_SCROLL
| SWT.V_SCROLL | SWT.BORDER);
viewer.setComparator(new ViewerComparator() {
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.viewers.ViewerComparator#compare(org.eclipse.jface.viewers.Viewer,
* java.lang.Object, java.lang.Object)
*/
public int compare(Viewer testViewer, Object e1, Object e2) {
return ((Comparable) e1).compareTo(e2);
}
});
ProgressViewerContentProvider provider = getContentProvider();
viewer.setContentProvider(provider);
viewer.setInput(provider);
viewer.setLabelProvider(new ProgressLabelProvider());
GridData data = new GridData(GridData.GRAB_HORIZONTAL
| GridData.GRAB_VERTICAL | GridData.FILL_BOTH);
data.horizontalSpan = 2;
int heightHint = convertHeightInCharsToPixels(10);
data.heightHint = heightHint;
viewer.getControl().setLayoutData(data);
}
/**
* Return the content provider used for the receiver.
*
* @return ProgressTreeContentProvider
*/
private ProgressViewerContentProvider getContentProvider() {
return new ProgressViewerContentProvider(viewer, true, false) {
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.internal.progress.ProgressViewerContentProvider#getElements(java.lang.Object)
*/
public Object[] getElements(Object inputElement) {
Object[] elements = super.getElements(inputElement);
Object[] result = new Object[elements.length + 1];
System.arraycopy(elements, 0, result, 1, elements.length);
result[0] = blockedElement;
return result;
}
};
}
/**
* Clear the cursors in the dialog.
*/
private void clearCursors() {
clearCursor(cancelSelected);
clearCursor(getShell());
if (arrowCursor != null) {
arrowCursor.dispose();
}
if (waitCursor != null) {
waitCursor.dispose();
}
arrowCursor = null;
waitCursor = null;
}
/**
* Clear the cursor on the supplied control.
*
* @param control
*/
private void clearCursor(Control control) {
if (control != null && !control.isDisposed()) {
control.setCursor(null);
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.window.Window#configureShell(org.eclipse.swt.widgets.Shell)
*/
protected void configureShell(Shell shell) {
super.configureShell(shell);
shell.setText(ProgressMessages.BlockedJobsDialog_BlockedTitle);
if (waitCursor == null) {
waitCursor = new Cursor(shell.getDisplay(), SWT.CURSOR_WAIT);
}
shell.setCursor(waitCursor);
}
/**
* This method sets the message in the message label.
*
* @param messageString -
* the String for the message area
*/
private void setMessage(String messageString) {
// must not set null text in a label
message = messageString == null ? "" : messageString; //$NON-NLS-1$
if (messageLabel == null || messageLabel.isDisposed()) {
return;
}
messageLabel.setText(message);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.dialogs.IconAndMessageDialog#getImage()
*/
protected Image getImage() {
return getInfoImage();
}
/**
* Returns the progress monitor being used for this dialog. This allows
* recursive blockages to also respond to cancelation.
*
* @return IProgressMonitor
*/
public IProgressMonitor getProgressMonitor() {
return blockingMonitor;
}
/**
* Requests that the blocked jobs dialog be closed. The supplied monitor
* must be the same one that was passed to the createBlockedDialog method.
*
* @param monitor
* @return IProgressMonitor
*/
public boolean close(IProgressMonitor monitor) {
// ignore requests to close the dialog from all but the first monitor
if (blockingMonitor != monitor) {
return false;
}
return close();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.dialogs.Dialog#close()
*/
public boolean close() {
// Clear the singleton first
singleton = null;
clearCursors();
return super.close();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.dialogs.IconAndMessageDialog#createButtonBar(org.eclipse.swt.widgets.Composite)
*/
protected Control createButtonBar(Composite parent) {
// Do nothing here as we want no buttons
return parent;
}
/**
* @param taskName
* The blockedTaskName to set.
*/
void setBlockedTaskName(String taskName) {
this.blockedTaskName = taskName;
}
}