Bug 25608 [Dialogs] ProgressMonitorDialog won't cancel unless it's forked
On ProgressMonitorDialog, there's a method: public void run(boolean fork, boolean cancelable, IRunnableWithProgress runnable) If the value of "fork" is false, the dialog cannot be canceled. The cancel button remains enabled and isCanceled() always returns false. The following code demonstrates this behaviour. (I chose to enable the popup menu extension on one IProject.) package org.myco.action; import java.lang.reflect.InvocationTargetException; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jface.action.IAction; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.MessageBox; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IActionDelegate; public class MyMenuAction implements IActionDelegate { private ISelection _currentSelection = null; private Shell _shell = null; public MyMenuAction() { super(); Display display = Display.getCurrent(); _shell = (display == null) ? null : display.getActiveShell(); } private void displayMessage(String title, String message, int iIconType) { MessageBox messageBox = new MessageBox(_shell, org.eclipse.swt.SWT.OK | iIconType | org.eclipse.swt.SWT.APPLICATION_MODAL); messageBox.setMessage(message); messageBox.setText(title); messageBox.open(); } public ProgressMonitorDialog getProgressMonitorDialog() { return new ProgressMonitorDialog(_shell); } private ISelection getCurrentSelection() { return _currentSelection; } private IProject getSelected() { ISelection selection = getCurrentSelection(); if ((selection == null) || selection.isEmpty() || !(selection instanceof IStructuredSelection)) { return null; } Object element = ((IStructuredSelection)selection).getFirstElement(); if(element instanceof IProject) { return (IProject)element; } if(element instanceof IJavaProject) { return ((IJavaProject)element).getProject(); } return null; } public void selectionChanged(IAction action, ISelection selection) { _currentSelection = selection; action.setEnabled(true); } public void run(IAction action) { final IProject project = getSelected(); if(project == null) { displayMessage("MyMenuAction Title", "No project selected", org.eclipse.swt.SWT.ICON_INFORMATION); return; } try { ProgressMonitorDialog dialog = getProgressMonitorDialog(); IRunnableWithProgress runnable = new IRunnableWithProgress() { public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { boolean isCanceled = false; for(int j=0; j<100000; j++) { if(monitor.isCanceled()) { isCanceled = true; System.out.println("Monitor was cancelled for " + project.getName() + " on iteration " + j); break; } monitor.subTask("Task " + j); } if(!isCanceled) { System.out.println("Monitor was never cancelled."); } } }; dialog.run(false, true, runnable); // false==!fork, true==cancelable // dialog.run(true, true, runnable); // true==fork, true==cancelable } catch (InvocationTargetException exc) { exc.printStackTrace(); } catch (InterruptedException exc) { exc.printStackTrace(); } } }
bundles/org.eclipse.ui.workbench/extensions/org/eclipse/jface/dialogs/ProgressMonitorDialog.java
/**
 * Enables the cancel button (asynchronously).
 */
private void asyncSetOperationCancelButtonEnabled(final boolean b) {
	if (getShell() != null) {
		getShell().getDisplay().asyncExec(new Runnable() {
			public void run() {
				setOperationCancelButtonEnabled(b);
			}
		});
	}
}
/* (non-Javadoc)
 * Method declared on Window.
 */
/**
 * The <code>ProgressMonitorDialog</code> implementation of this method
 * only closes the dialog if there are no currently running runnables.
 */
public boolean close() {
	if (runningRunnables <= 0) {
		if (cancel != null && !cancel.isDisposed()) {
			cancel.setCursor(null);
		}
		Shell shell = getShell();
		if (shell != null && !shell.isDisposed()) {
			shell.setCursor(null);
		}
		if (arrowCursor != null)
			arrowCursor.dispose();