001: /*******************************************************************************
002: * Copyright (c) 2003, 2007 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 - Initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.internal.progress;
011:
012: import java.lang.reflect.InvocationTargetException;
013: import java.util.Collection;
014: import java.util.Collections;
015: import java.util.HashSet;
016:
017: import org.eclipse.core.runtime.Assert;
018: import org.eclipse.core.runtime.IProgressMonitor;
019: import org.eclipse.core.runtime.IStatus;
020: import org.eclipse.core.runtime.Status;
021: import org.eclipse.core.runtime.jobs.IJobChangeEvent;
022: import org.eclipse.core.runtime.jobs.IJobChangeListener;
023: import org.eclipse.core.runtime.jobs.ISchedulingRule;
024: import org.eclipse.core.runtime.jobs.Job;
025: import org.eclipse.core.runtime.jobs.JobChangeAdapter;
026: import org.eclipse.jface.operation.IRunnableContext;
027: import org.eclipse.jface.operation.IRunnableWithProgress;
028: import org.eclipse.jface.resource.ImageDescriptor;
029: import org.eclipse.jface.util.IPropertyChangeListener;
030: import org.eclipse.swt.SWT;
031: import org.eclipse.swt.graphics.Cursor;
032: import org.eclipse.swt.graphics.Image;
033: import org.eclipse.swt.widgets.Control;
034: import org.eclipse.swt.widgets.Display;
035: import org.eclipse.swt.widgets.Shell;
036: import org.eclipse.ui.IWorkbenchPart;
037: import org.eclipse.ui.PlatformUI;
038: import org.eclipse.ui.internal.PartSite;
039: import org.eclipse.ui.internal.WorkbenchPlugin;
040: import org.eclipse.ui.part.WorkbenchPart;
041: import org.eclipse.ui.progress.IProgressService;
042: import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
043: import org.eclipse.ui.progress.WorkbenchJob;
044:
045: /**
046: * The WorkbenchSiteProgressService is the concrete implementation of the
047: * WorkbenchSiteProgressService used by the workbench components.
048: */
049: public class WorkbenchSiteProgressService implements
050: IWorkbenchSiteProgressService, IJobBusyListener {
051: PartSite site;
052:
053: private Collection busyJobs = Collections
054: .synchronizedSet(new HashSet());
055:
056: private Object busyLock = new Object();
057:
058: IJobChangeListener listener;
059:
060: IPropertyChangeListener[] changeListeners = new IPropertyChangeListener[0];
061:
062: private Cursor waitCursor;
063:
064: private SiteUpdateJob updateJob;
065:
066: /**
067: * Flag that keeps state from calls to {@link #showBusy(boolean)}
068: */
069: private int busyCount = 0;
070:
071: private class SiteUpdateJob extends WorkbenchJob {
072: private boolean busy;
073:
074: private boolean useWaitCursor = false;
075:
076: Object lock = new Object();
077:
078: /**
079: * Set whether we are updating with the wait or busy cursor.
080: *
081: * @param cursorState
082: */
083: void setBusy(boolean cursorState) {
084: synchronized (lock) {
085: busy = cursorState;
086: }
087: }
088:
089: private SiteUpdateJob() {
090: super (
091: ProgressMessages.WorkbenchSiteProgressService_CursorJob);
092: }
093:
094: /**
095: * Get the wait cursor. Initialize it if required.
096: * @param display the display to create the cursor on.
097: * @return the created cursor
098: */
099: private Cursor getWaitCursor(Display display) {
100: if (waitCursor == null) {
101: waitCursor = new Cursor(display, SWT.CURSOR_APPSTARTING);
102: }
103: return waitCursor;
104: }
105:
106: /*
107: * (non-Javadoc)
108: *
109: * @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor)
110: */
111: public IStatus runInUIThread(IProgressMonitor monitor) {
112: Control control = site.getPane().getControl();
113: if (control == null || control.isDisposed()) {
114: return Status.CANCEL_STATUS;
115: }
116: synchronized (lock) {
117: //Update cursors if we are doing that
118: if (useWaitCursor) {
119: Cursor cursor = null;
120: if (busy) {
121: cursor = getWaitCursor(control.getDisplay());
122: }
123: control.setCursor(cursor);
124: }
125: site.getPane().setBusy(busy);
126: IWorkbenchPart part = site.getPart();
127: if (part instanceof WorkbenchPart) {
128: ((WorkbenchPart) part).showBusy(busy);
129: }
130: }
131: return Status.OK_STATUS;
132: }
133:
134: void clearCursors() {
135: if (waitCursor != null) {
136: waitCursor.dispose();
137: waitCursor = null;
138: }
139: }
140: }
141:
142: /**
143: * Create a new instance of the receiver with a site of partSite
144: *
145: * @param partSite
146: * PartSite.
147: */
148: public WorkbenchSiteProgressService(final PartSite partSite) {
149: site = partSite;
150: updateJob = new SiteUpdateJob();
151: updateJob.setSystem(true);
152: }
153:
154: /**
155: * Dispose the resources allocated by the receiver.
156: *
157: */
158: public void dispose() {
159: if (updateJob != null) {
160: updateJob.cancel();
161: }
162:
163: ProgressManager.getInstance().removeListener(this );
164:
165: if (waitCursor == null) {
166: return;
167: }
168: waitCursor.dispose();
169: waitCursor = null;
170: }
171:
172: /*
173: * (non-Javadoc)
174: *
175: * @see org.eclipse.ui.progress.IProgressService#busyCursorWhile(org.eclipse.jface.operation.IRunnableWithProgress)
176: */
177: public void busyCursorWhile(IRunnableWithProgress runnable)
178: throws InvocationTargetException, InterruptedException {
179: getWorkbenchProgressService().busyCursorWhile(runnable);
180: }
181:
182: /*
183: * (non-Javadoc)
184: *
185: * @see org.eclipse.ui.progress.IWorkbenchSiteProgressService#schedule(org.eclipse.core.runtime.jobs.Job,
186: * long, boolean)
187: */
188: public void schedule(Job job, long delay, boolean useHalfBusyCursor) {
189: job.addJobChangeListener(getJobChangeListener(job,
190: useHalfBusyCursor));
191: job.schedule(delay);
192: }
193:
194: /*
195: * (non-Javadoc)
196: *
197: * @see org.eclipse.ui.progress.IWorkbenchSiteProgressService#schedule(org.eclipse.core.runtime.jobs.Job,
198: * int)
199: */
200: public void schedule(Job job, long delay) {
201: schedule(job, delay, false);
202: }
203:
204: /*
205: * (non-Javadoc)
206: *
207: * @see org.eclipse.ui.progress.IWorkbenchSiteProgressService#schedule(org.eclipse.core.runtime.jobs.Job)
208: */
209: public void schedule(Job job) {
210: schedule(job, 0L, false);
211: }
212:
213: /*
214: * (non-Javadoc)
215: *
216: * @see org.eclipse.ui.progress.IWorkbenchSiteProgressService#showBusyForFamily(java.lang.Object)
217: */
218: public void showBusyForFamily(Object family) {
219: ProgressManager.getInstance().addListenerToFamily(family, this );
220: }
221:
222: /**
223: * Get the job change listener for this site.
224: *
225: * @param job
226: * @param useHalfBusyCursor
227: * @return IJobChangeListener
228: */
229: public IJobChangeListener getJobChangeListener(final Job job,
230: boolean useHalfBusyCursor) {
231: if (listener == null) {
232: updateJob.useWaitCursor = useHalfBusyCursor;
233: listener = new JobChangeAdapter() {
234: /*
235: * (non-Javadoc)
236: *
237: * @see org.eclipse.core.runtime.jobs.JobChangeAdapter#aboutToRun(org.eclipse.core.runtime.jobs.IJobChangeEvent)
238: */
239: public void aboutToRun(IJobChangeEvent event) {
240: incrementBusy(event.getJob());
241: }
242:
243: /*
244: * (non-Javadoc)
245: *
246: * @see org.eclipse.core.runtime.jobs.JobChangeAdapter#done(org.eclipse.core.runtime.jobs.IJobChangeEvent)
247: */
248: public void done(IJobChangeEvent event) {
249: decrementBusy(event.getJob());
250: }
251: };
252: }
253: return listener;
254: }
255:
256: /*
257: * (non-Javadoc)
258: *
259: * @see org.eclipse.ui.internal.progress.IJobBusyListener#decrementBusy(org.eclipse.core.runtime.jobs.Job)
260: */
261: public void decrementBusy(Job job) {
262: synchronized (busyLock) {
263: if (!busyJobs.contains(job)) {
264: return;
265: }
266: busyJobs.remove(job);
267: }
268: try {
269: decrementBusy();
270: } catch (Exception ex) {
271: // protecting against assertion failures
272: WorkbenchPlugin.log(ex);
273: }
274: }
275:
276: /*
277: * (non-Javadoc)
278: *
279: * @see org.eclipse.ui.internal.progress.IJobBusyListener#incrementBusy(org.eclipse.core.runtime.jobs.Job)
280: */
281: public void incrementBusy(Job job) {
282: synchronized (busyLock) {
283: if (busyJobs.contains(job)) {
284: return;
285: }
286: busyJobs.add(job);
287: }
288: incrementBusy();
289: }
290:
291: /*
292: * (non-Javadoc)
293: *
294: * @see org.eclipse.ui.progress.IWorkbenchSiteProgressService#warnOfContentChange()
295: */
296: public void warnOfContentChange() {
297: site.getPane().showHighlight();
298: }
299:
300: /*
301: * (non-Javadoc)
302: *
303: * @see org.eclipse.ui.progress.IProgressService#showInDialog(org.eclipse.swt.widgets.Shell,
304: * org.eclipse.core.runtime.jobs.Job)
305: */
306: public void showInDialog(Shell shell, Job job) {
307: getWorkbenchProgressService().showInDialog(shell, job);
308: }
309:
310: /**
311: * Get the progress service for the workbnech,
312: *
313: * @return IProgressService
314: */
315: private IProgressService getWorkbenchProgressService() {
316: return site.getWorkbenchWindow().getWorkbench()
317: .getProgressService();
318: }
319:
320: /*
321: * (non-Javadoc)
322: *
323: * @see org.eclipse.jface.operation.IRunnableContext#run(boolean, boolean,
324: * org.eclipse.jface.operation.IRunnableWithProgress)
325: */
326: public void run(boolean fork, boolean cancelable,
327: IRunnableWithProgress runnable)
328: throws InvocationTargetException, InterruptedException {
329: getWorkbenchProgressService().run(fork, cancelable, runnable);
330: }
331:
332: /*
333: * (non-Javadoc)
334: * @see org.eclipse.ui.progress.IProgressService#runInUI(org.eclipse.jface.operation.IRunnableContext, org.eclipse.jface.operation.IRunnableWithProgress, org.eclipse.core.runtime.jobs.ISchedulingRule)
335: */
336: public void runInUI(IRunnableContext context,
337: IRunnableWithProgress runnable, ISchedulingRule rule)
338: throws InvocationTargetException, InterruptedException {
339: getWorkbenchProgressService().runInUI(context, runnable, rule);
340: }
341:
342: /* (non-Javadoc)
343: * @see org.eclipse.ui.progress.IProgressService#getLongOperationTime()
344: */
345: public int getLongOperationTime() {
346: return getWorkbenchProgressService().getLongOperationTime();
347: }
348:
349: /* (non-Javadoc)
350: * @see org.eclipse.ui.progress.IProgressService#registerIconForFamily(org.eclipse.jface.resource.ImageDescriptor, java.lang.Object)
351: */
352: public void registerIconForFamily(ImageDescriptor icon,
353: Object family) {
354: getWorkbenchProgressService().registerIconForFamily(icon,
355: family);
356: }
357:
358: /* (non-Javadoc)
359: * @see org.eclipse.ui.progress.IProgressService#getIconFor(org.eclipse.core.runtime.jobs.Job)
360: */
361: public Image getIconFor(Job job) {
362: return getWorkbenchProgressService().getIconFor(job);
363: }
364:
365: /* (non-Javadoc)
366: * @see org.eclipse.ui.progress.IWorkbenchSiteProgressService#showBusy(boolean)
367: */
368: public void incrementBusy() {
369: synchronized (busyLock) {
370: this .busyCount++;
371: if (busyCount != 1) {
372: return;
373: }
374: updateJob.setBusy(true);
375: }
376: if (PlatformUI.isWorkbenchRunning()) {
377: updateJob.schedule(100);
378: } else {
379: updateJob.cancel();
380: }
381: }
382:
383: /* (non-Javadoc)
384: * @see org.eclipse.ui.progress.IWorkbenchSiteProgressService#showBusy(boolean)
385: */
386: public void decrementBusy() {
387: synchronized (busyLock) {
388: Assert
389: .isTrue(
390: busyCount > 0,
391: "Ignoring unexpected call to IWorkbenchSiteProgressService.decrementBusy(). This might be due to an earlier call to this method."); //$NON-NLS-1$
392: this .busyCount--;
393: if (busyCount != 0) {
394: return;
395: }
396: updateJob.setBusy(false);
397: }
398: if (PlatformUI.isWorkbenchRunning()) {
399: updateJob.schedule(100);
400: } else {
401: updateJob.cancel();
402: }
403: }
404: }
|