001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jface.operation;
011:
012: import org.eclipse.core.runtime.IProgressMonitor;
013: import org.eclipse.core.runtime.IProgressMonitorWithBlocking;
014: import org.eclipse.core.runtime.IStatus;
015: import org.eclipse.core.runtime.ProgressMonitorWrapper;
016: import org.eclipse.jface.dialogs.Dialog;
017: import org.eclipse.core.runtime.Assert;
018: import org.eclipse.swt.widgets.Display;
019:
020: /**
021: * A progress monitor that accumulates <code>worked</code> and <code>subtask</code>
022: * calls in the following way by wrapping a standard progress monitor:
023: * <ul>
024: * <li> When a <code>worked</code> or <code>subtask</code> call occurs the first time,
025: * the progress monitor posts a runnable into the asynchronous SWT event queue.
026: * </li>
027: * <li> Subsequent calls to <code>worked</code> or <code>subtask</code> do not post
028: * a new runnable as long as a previous runnable still exists in the SWT event
029: * queue. In this case, the progress monitor just updates the internal state of
030: * the runnable that waits in the SWT event queue for its execution. If no runnable
031: * exists, a new one is created and posted into the event queue.
032: * </ul>
033: * <p>
034: * This class is internal to the framework; clients outside JFace should not
035: * use this class.
036: * </p>
037: */
038: /* package */class AccumulatingProgressMonitor extends
039: ProgressMonitorWrapper {
040:
041: /**
042: * The display.
043: */
044: private Display display;
045:
046: /**
047: * The collector, or <code>null</code> if none.
048: */
049: private Collector collector;
050:
051: private String currentTask = ""; //$NON-NLS-1$
052:
053: private class Collector implements Runnable {
054: private String subTask;
055:
056: private double worked;
057:
058: private IProgressMonitor monitor;
059:
060: /**
061: * Create a new collector.
062: * @param subTask
063: * @param work
064: * @param monitor
065: */
066: public Collector(String subTask, double work,
067: IProgressMonitor monitor) {
068: this .subTask = subTask;
069: this .worked = work;
070: this .monitor = monitor;
071: }
072:
073: /**
074: * Add worked to the work.
075: * @param workedIncrement
076: */
077: public void worked(double workedIncrement) {
078: this .worked = this .worked + workedIncrement;
079: }
080:
081: /**
082: * Set the subTask name.
083: * @param subTaskName
084: */
085: public void subTask(String subTaskName) {
086: this .subTask = subTaskName;
087: }
088:
089: /**
090: * Run the collector.
091: */
092: public void run() {
093: clearCollector(this );
094: if (subTask != null) {
095: monitor.subTask(subTask);
096: }
097: if (worked > 0) {
098: monitor.internalWorked(worked);
099: }
100: }
101: }
102:
103: /**
104: * Creates an accumulating progress monitor wrapping the given one
105: * that uses the given display.
106: *
107: * @param monitor the actual progress monitor to be wrapped
108: * @param display the SWT display used to forward the calls
109: * to the wrapped progress monitor
110: */
111: public AccumulatingProgressMonitor(IProgressMonitor monitor,
112: Display display) {
113: super (monitor);
114: Assert.isNotNull(display);
115: this .display = display;
116: }
117:
118: /* (non-Javadoc)
119: * Method declared on IProgressMonitor.
120: */
121: public void beginTask(final String name, final int totalWork) {
122: synchronized (this ) {
123: collector = null;
124: }
125: display.syncExec(new Runnable() {
126: public void run() {
127: currentTask = name;
128: getWrappedProgressMonitor().beginTask(name, totalWork);
129: }
130: });
131: }
132:
133: /**
134: * Clears the collector object used to accumulate work and subtask calls
135: * if it matches the given one.
136: * @param collectorToClear
137: */
138: private synchronized void clearCollector(Collector collectorToClear) {
139: // Check if the accumulator is still using the given collector.
140: // If not, don't clear it.
141: if (this .collector == collectorToClear) {
142: this .collector = null;
143: }
144: }
145:
146: /**
147: * Creates a collector object to accumulate work and subtask calls.
148: * @param subTask
149: * @param work
150: */
151: private void createCollector(String subTask, double work) {
152: collector = new Collector(subTask, work,
153: getWrappedProgressMonitor());
154: display.asyncExec(collector);
155: }
156:
157: /* (non-Javadoc)
158: * Method declared on IProgressMonitor.
159: */
160: public void done() {
161: synchronized (this ) {
162: collector = null;
163: }
164: display.syncExec(new Runnable() {
165: public void run() {
166: getWrappedProgressMonitor().done();
167: }
168: });
169: }
170:
171: /* (non-Javadoc)
172: * Method declared on IProgressMonitor.
173: */
174: public synchronized void internalWorked(final double work) {
175: if (collector == null) {
176: createCollector(null, work);
177: } else {
178: collector.worked(work);
179: }
180: }
181:
182: /* (non-Javadoc)
183: * Method declared on IProgressMonitor.
184: */
185: public void setTaskName(final String name) {
186: synchronized (this ) {
187: collector = null;
188: }
189: display.syncExec(new Runnable() {
190: public void run() {
191: currentTask = name;
192: getWrappedProgressMonitor().setTaskName(name);
193: }
194: });
195: }
196:
197: /* (non-Javadoc)
198: * Method declared on IProgressMonitor.
199: */
200: public synchronized void subTask(final String name) {
201: if (collector == null) {
202: createCollector(name, 0);
203: } else {
204: collector.subTask(name);
205: }
206: }
207:
208: /* (non-Javadoc)
209: * Method declared on IProgressMonitor.
210: */
211: public synchronized void worked(int work) {
212: internalWorked(work);
213: }
214:
215: /* (non-Javadoc)
216: * @see org.eclipse.core.runtime.ProgressMonitorWrapper#clearBlocked()
217: */
218: public void clearBlocked() {
219:
220: //If this is a monitor that can report blocking do so.
221: //Don't bother with a collector as this should only ever
222: //happen once and prevent any more progress.
223: final IProgressMonitor pm = getWrappedProgressMonitor();
224: if (!(pm instanceof IProgressMonitorWithBlocking)) {
225: return;
226: }
227:
228: display.asyncExec(new Runnable() {
229: /* (non-Javadoc)
230: * @see java.lang.Runnable#run()
231: */
232: public void run() {
233: ((IProgressMonitorWithBlocking) pm).clearBlocked();
234: Dialog.getBlockedHandler().clearBlocked();
235: }
236: });
237: }
238:
239: /* (non-Javadoc)
240: * @see org.eclipse.core.runtime.ProgressMonitorWrapper#setBlocked(org.eclipse.core.runtime.IStatus)
241: */
242: public void setBlocked(final IStatus reason) {
243: //If this is a monitor that can report blocking do so.
244: //Don't bother with a collector as this should only ever
245: //happen once and prevent any more progress.
246: final IProgressMonitor pm = getWrappedProgressMonitor();
247: if (!(pm instanceof IProgressMonitorWithBlocking)) {
248: return;
249: }
250:
251: display.asyncExec(new Runnable() {
252: /* (non-Javadoc)
253: * @see java.lang.Runnable#run()
254: */
255: public void run() {
256: ((IProgressMonitorWithBlocking) pm).setBlocked(reason);
257: //Do not give a shell as we want it to block until it opens.
258: Dialog.getBlockedHandler().showBlocked(pm, reason,
259: currentTask);
260: }
261: });
262: }
263: }
|