blob: 10c6764cefae3a219a03e099ba036c0467f1e72b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2003, 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 - Initial API and implementation
* Remy Chi Jian Suen (Versant Corporation) - bug 255005
*******************************************************************************/
package org.eclipse.ui.internal.progress;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.IJobChangeListener;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.jface.operation.IRunnableContext;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.PartSite;
import org.eclipse.ui.internal.WorkbenchPlugin;
import org.eclipse.ui.part.WorkbenchPart;
import org.eclipse.ui.progress.IProgressService;
import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
import org.eclipse.ui.progress.WorkbenchJob;
/**
* The WorkbenchSiteProgressService is the concrete implementation of the
* WorkbenchSiteProgressService used by the workbench components.
*/
public class WorkbenchSiteProgressService implements
IWorkbenchSiteProgressService, IJobBusyListener {
PartSite site;
private Collection busyJobs = Collections.synchronizedSet(new HashSet());
private Object busyLock = new Object();
IPropertyChangeListener[] changeListeners = new IPropertyChangeListener[0];
private Cursor waitCursor;
private int waitCursorJobCount;
private Object waitCursorLock = new Object();
private SiteUpdateJob updateJob;
/**
* Flag that keeps state from calls to {@link #showBusy(boolean)}
*/
private int busyCount = 0;
public class SiteUpdateJob extends WorkbenchJob {
private boolean busy;
Object lock = new Object();
/**
* Set whether we are updating with the wait or busy cursor.
*
* @param cursorState
*/
void setBusy(boolean cursorState) {
synchronized (lock) {
busy = cursorState;
}
}
private SiteUpdateJob() {
super(ProgressMessages.WorkbenchSiteProgressService_CursorJob);
}
/**
* Get the wait cursor. Initialize it if required.
*
* @param display
* the display to create the cursor on.
* @return the created cursor
*/
private Cursor getWaitCursor(Display display) {
if (waitCursor == null) {
waitCursor = new Cursor(display, SWT.CURSOR_APPSTARTING);
}
return waitCursor;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime
* .IProgressMonitor)
*/
public IStatus runInUIThread(IProgressMonitor monitor) {
Control control = site.getPane().getControl();
if (control == null || control.isDisposed()) {
return Status.CANCEL_STATUS;
}
synchronized (lock) {
// Update cursors if we are doing that
Cursor cursor = null;
if (waitCursorJobCount != 0) {
// at least one job which is running has requested for wait
// cursor
cursor = getWaitCursor(control.getDisplay());
}
control.setCursor(cursor);
site.getPane().setBusy(busy);
IWorkbenchPart part = site.getPart();
if (part instanceof WorkbenchPart) {
((WorkbenchPart) part).showBusy(busy);
}
}
return Status.OK_STATUS;
}
void clearCursors() {
if (waitCursor != null) {
waitCursor.dispose();
waitCursor = null;
}
}
}
/**
* Create a new instance of the receiver with a site of partSite
*
* @param partSite
* PartSite.
*/
public WorkbenchSiteProgressService(final PartSite partSite) {
site = partSite;
updateJob = new SiteUpdateJob();
updateJob.setSystem(true);
}
/**
* Dispose the resources allocated by the receiver.
*
*/
public void dispose() {
if (updateJob != null) {
updateJob.cancel();
}
ProgressManager.getInstance().removeListener(this);
if (waitCursor == null) {
return;
}
waitCursor.dispose();
waitCursor = null;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.ui.progress.IProgressService#busyCursorWhile(org.eclipse.
* jface.operation.IRunnableWithProgress)
*/
public void busyCursorWhile(IRunnableWithProgress runnable)
throws InvocationTargetException, InterruptedException {
getWorkbenchProgressService().busyCursorWhile(runnable);
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.ui.progress.IWorkbenchSiteProgressService#schedule(org.eclipse
* .core.runtime.jobs.Job, long, boolean)
*/
public void schedule(Job job, long delay, boolean useHalfBusyCursor) {
job.addJobChangeListener(getJobChangeListener(useHalfBusyCursor));
job.schedule(delay);
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.ui.progress.IWorkbenchSiteProgressService#schedule(org.eclipse
* .core.runtime.jobs.Job, int)
*/
public void schedule(Job job, long delay) {
schedule(job, delay, false);
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.ui.progress.IWorkbenchSiteProgressService#schedule(org.eclipse
* .core.runtime.jobs.Job)
*/
public void schedule(Job job) {
schedule(job, 0L, false);
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.ui.progress.IWorkbenchSiteProgressService#showBusyForFamily
* (java.lang.Object)
*/
public void showBusyForFamily(Object family) {
ProgressManager.getInstance().addListenerToFamily(family, this);
}
/**
* Get the job change listener for this site.
*
* @param job
* @param useHalfBusyCursor
* @return IJobChangeListener
*/
public IJobChangeListener getJobChangeListener(
final boolean useHalfBusyCursor) {
return new JobChangeAdapter() {
/*
* (non-Javadoc)
*
* @see
* org.eclipse.core.runtime.jobs.JobChangeAdapter#aboutToRun(org
* .eclipse.core.runtime.jobs.IJobChangeEvent)
*/
public void aboutToRun(IJobChangeEvent event) {
if (useHalfBusyCursor) {
synchronized (waitCursorLock) {
waitCursorJobCount++;
}
}
incrementBusy(event.getJob());
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.core.runtime.jobs.JobChangeAdapter#done(org.eclipse
* .core.runtime.jobs.IJobChangeEvent)
*/
public void done(IJobChangeEvent event) {
if (useHalfBusyCursor) {
synchronized (waitCursorLock) {
waitCursorJobCount--;
}
}
Job job = event.getJob();
decrementBusy(job);
job.removeJobChangeListener(this);
}
};
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.ui.internal.progress.IJobBusyListener#decrementBusy(org.eclipse
* .core.runtime.jobs.Job)
*/
public void decrementBusy(Job job) {
synchronized (busyLock) {
if (!busyJobs.contains(job)) {
return;
}
busyJobs.remove(job);
}
try {
decrementBusy();
} catch (Exception ex) {
// protecting against assertion failures
WorkbenchPlugin.log(ex);
}
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.ui.internal.progress.IJobBusyListener#incrementBusy(org.eclipse
* .core.runtime.jobs.Job)
*/
public void incrementBusy(Job job) {
synchronized (busyLock) {
if (busyJobs.contains(job)) {
return;
}
busyJobs.add(job);
}
incrementBusy();
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.ui.progress.IWorkbenchSiteProgressService#warnOfContentChange
* ()
*/
public void warnOfContentChange() {
// site.getPane().showHighlight();
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.ui.progress.IProgressService#showInDialog(org.eclipse.swt
* .widgets.Shell, org.eclipse.core.runtime.jobs.Job)
*/
public void showInDialog(Shell shell, Job job) {
getWorkbenchProgressService().showInDialog(shell, job);
}
/**
* Get the progress service for the workbnech,
*
* @return IProgressService
*/
private IProgressService getWorkbenchProgressService() {
return site.getWorkbenchWindow().getWorkbench().getProgressService();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.operation.IRunnableContext#run(boolean, boolean,
* org.eclipse.jface.operation.IRunnableWithProgress)
*/
public void run(boolean fork, boolean cancelable,
IRunnableWithProgress runnable) throws InvocationTargetException,
InterruptedException {
getWorkbenchProgressService().run(fork, cancelable, runnable);
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.ui.progress.IProgressService#runInUI(org.eclipse.jface.operation
* .IRunnableContext, org.eclipse.jface.operation.IRunnableWithProgress,
* org.eclipse.core.runtime.jobs.ISchedulingRule)
*/
public void runInUI(IRunnableContext context,
IRunnableWithProgress runnable, ISchedulingRule rule)
throws InvocationTargetException, InterruptedException {
getWorkbenchProgressService().runInUI(context, runnable, rule);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.progress.IProgressService#getLongOperationTime()
*/
public int getLongOperationTime() {
return getWorkbenchProgressService().getLongOperationTime();
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.ui.progress.IProgressService#registerIconForFamily(org.eclipse
* .jface.resource.ImageDescriptor, java.lang.Object)
*/
public void registerIconForFamily(ImageDescriptor icon, Object family) {
getWorkbenchProgressService().registerIconForFamily(icon, family);
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.ui.progress.IProgressService#getIconFor(org.eclipse.core.
* runtime.jobs.Job)
*/
public Image getIconFor(Job job) {
return getWorkbenchProgressService().getIconFor(job);
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.ui.progress.IWorkbenchSiteProgressService#showBusy(boolean)
*/
public void incrementBusy() {
synchronized (busyLock) {
this.busyCount++;
if (busyCount != 1) {
return;
}
updateJob.setBusy(true);
}
if (PlatformUI.isWorkbenchRunning()) {
// updateJob.schedule(100);
} else {
updateJob.cancel();
}
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.ui.progress.IWorkbenchSiteProgressService#showBusy(boolean)
*/
public void decrementBusy() {
synchronized (busyLock) {
Assert
.isTrue(
busyCount > 0,
"Ignoring unexpected call to IWorkbenchSiteProgressService.decrementBusy(). This might be due to an earlier call to this method."); //$NON-NLS-1$
this.busyCount--;
if (busyCount != 0) {
return;
}
updateJob.setBusy(false);
}
if (PlatformUI.isWorkbenchRunning()) {
// updateJob.schedule(100);
} else {
updateJob.cancel();
}
}
/**
* This method is made public only for the tests. Clients should not be
* using this method
*
* @return the updateJob that updates the site
*/
public SiteUpdateJob getUpdateJob() {
return updateJob;
}
}