blob: a6388d62f11756f184dd9234f9ce821e8653d718 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2004 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.jface.operation;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IProgressMonitorWithBlocking;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.ProgressMonitorWrapper;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.util.Assert;
import org.eclipse.swt.widgets.Display;
/**
* A progress monitor that accumulates <code>worked</code> and <code>subtask</code>
* calls in the following way by wrapping a standard progress monitor:
* <ul>
* <li> When a <code>worked</code> or <code>subtask</code> call occurs the first time,
* the progress monitor posts a runnable into the asynchronous SWT event queue.
* </li>
* <li> Subsequent calls to <code>worked</code> or <code>subtask</code> do not post
* a new runnable as long as a previous runnable still exists in the SWT event
* queue. In this case, the progress monitor just updates the internal state of
* the runnable that waits in the SWT event queue for its execution. If no runnable
* exists, a new one is created and posted into the event queue.
* </ul>
* <p>
* This class is internal to the framework; clients outside JFace should not
* use this class.
* </p>
*/
/* package */class AccumulatingProgressMonitor extends ProgressMonitorWrapper {
/**
* The display.
*/
private Display display;
/**
* The collector, or <code>null</code> if none.
*/
private Collector collector;
private String currentTask = ""; //$NON-NLS-1$
private class Collector implements Runnable {
private String subTask;
private double worked;
private IProgressMonitor monitor;
/**
* Create a new collector.
* @param subTask
* @param work
* @param monitor
*/
public Collector(String subTask, double work, IProgressMonitor monitor) {
this.subTask = subTask;
this.worked = work;
this.monitor = monitor;
}
/**
* Add worked to the work.
* @param workedIncrement
*/
public void worked(double workedIncrement) {
this.worked = this.worked + workedIncrement;
}
/**
* Set the subTask name.
* @param subTaskName
*/
public void subTask(String subTaskName) {
this.subTask = subTaskName;
}
/**
* Run the collector.
*/
public void run() {
clearCollector(this);
if (subTask != null)
monitor.subTask(subTask);
if (worked > 0)
monitor.internalWorked(worked);
}
}
/**
* Creates an accumulating progress monitor wrapping the given one
* that uses the given display.
*
* @param monitor the actual progress monitor to be wrapped
* @param display the SWT display used to forward the calls
* to the wrapped progress monitor
*/
public AccumulatingProgressMonitor(IProgressMonitor monitor, Display display) {
super(monitor);
Assert.isNotNull(display);
this.display = display;
}
/* (non-Javadoc)
* Method declared on IProgressMonitor.
*/
public void beginTask(final String name, final int totalWork) {
synchronized (this) {
collector = null;
}
display.syncExec(new Runnable() {
public void run() {
currentTask = name;
getWrappedProgressMonitor().beginTask(name, totalWork);
}
});
}
/**
* Clears the collector object used to accumulate work and subtask calls
* if it matches the given one.
* @param collectorToClear
*/
private synchronized void clearCollector(Collector collectorToClear) {
// Check if the accumulator is still using the given collector.
// If not, don't clear it.
if (this.collector == collectorToClear)
this.collector = null;
}
/**
* Creates a collector object to accumulate work and subtask calls.
* @param subTask
* @param work
*/
private void createCollector(String subTask, double work) {
collector = new Collector(subTask, work, getWrappedProgressMonitor());
display.asyncExec(collector);
}
/* (non-Javadoc)
* Method declared on IProgressMonitor.
*/
public void done() {
synchronized (this) {
collector = null;
}
display.syncExec(new Runnable() {
public void run() {
getWrappedProgressMonitor().done();
}
});
}
/* (non-Javadoc)
* Method declared on IProgressMonitor.
*/
public synchronized void internalWorked(final double work) {
if (collector == null) {
createCollector(null, work);
} else {
collector.worked(work);
}
}
/* (non-Javadoc)
* Method declared on IProgressMonitor.
*/
public void setTaskName(final String name) {
synchronized (this) {
collector = null;
}
display.syncExec(new Runnable() {
public void run() {
currentTask = name;
getWrappedProgressMonitor().setTaskName(name);
}
});
}
/* (non-Javadoc)
* Method declared on IProgressMonitor.
*/
public synchronized void subTask(final String name) {
if (collector == null) {
createCollector(name, 0);
} else {
collector.subTask(name);
}
}
/* (non-Javadoc)
* Method declared on IProgressMonitor.
*/
public synchronized void worked(int work) {
internalWorked(work);
}
/* (non-Javadoc)
* @see org.eclipse.core.runtime.ProgressMonitorWrapper#clearBlocked()
*/
public void clearBlocked() {
//If this is a monitor that can report blocking do so.
//Don't bother with a collector as this should only ever
//happen once and prevent any more progress.
final IProgressMonitor pm = getWrappedProgressMonitor();
if (!(pm instanceof IProgressMonitorWithBlocking))
return;
display.asyncExec(new Runnable() {
/* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
public void run() {
((IProgressMonitorWithBlocking) pm).clearBlocked();
Dialog.getBlockedHandler().clearBlocked();
}
});
}
/* (non-Javadoc)
* @see org.eclipse.core.runtime.ProgressMonitorWrapper#setBlocked(org.eclipse.core.runtime.IStatus)
*/
public void setBlocked(final IStatus reason) {
//If this is a monitor that can report blocking do so.
//Don't bother with a collector as this should only ever
//happen once and prevent any more progress.
final IProgressMonitor pm = getWrappedProgressMonitor();
if (!(pm instanceof IProgressMonitorWithBlocking))
return;
display.asyncExec(new Runnable() {
/* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
public void run() {
((IProgressMonitorWithBlocking) pm).setBlocked(reason);
//Do not give a shell as we want it to block until it opens.
Dialog.getBlockedHandler().showBlocked(pm, reason, currentTask);
}
});
}
}