diff options
Diffstat (limited to 'bundles/org.eclipse.e4.ui.progress/src/org/eclipse/e4/ui/progress/internal/ProgressServiceImpl.java')
-rw-r--r-- | bundles/org.eclipse.e4.ui.progress/src/org/eclipse/e4/ui/progress/internal/ProgressServiceImpl.java | 353 |
1 files changed, 353 insertions, 0 deletions
diff --git a/bundles/org.eclipse.e4.ui.progress/src/org/eclipse/e4/ui/progress/internal/ProgressServiceImpl.java b/bundles/org.eclipse.e4.ui.progress/src/org/eclipse/e4/ui/progress/internal/ProgressServiceImpl.java new file mode 100644 index 00000000000..48942809f68 --- /dev/null +++ b/bundles/org.eclipse.e4.ui.progress/src/org/eclipse/e4/ui/progress/internal/ProgressServiceImpl.java @@ -0,0 +1,353 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 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.e4.ui.progress.internal; + +import java.lang.reflect.InvocationTargetException; +import java.util.Enumeration; +import java.util.Hashtable; + +import javax.inject.Inject; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.IJobManager; +import org.eclipse.core.runtime.jobs.ISchedulingRule; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.e4.core.di.annotations.Optional; +import org.eclipse.e4.ui.di.UISynchronize; +import org.eclipse.e4.ui.progress.IProgressConstants; +import org.eclipse.e4.ui.progress.IProgressService; +import org.eclipse.e4.ui.progress.UIJob; +import org.eclipse.e4.ui.progress.internal.legacy.EventLoopProgressMonitor; +import org.eclipse.e4.ui.progress.internal.legacy.PlatformUI; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.operation.IRunnableContext; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.resource.ImageRegistry; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.swt.custom.BusyIndicator; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; + +public class ProgressServiceImpl implements IProgressService { + + private static final String IMAGE_KEY = "org.eclipse.ui.progress.images"; //$NON-NLS-1$ + + private Hashtable imageKeyTable = new Hashtable(); + + @Inject + @Optional + ProgressManager progressManager; + + @Inject + @Optional + FinishedJobs finishedJobs; + + @Inject + @Optional + ContentProviderFactory contentProviderFactory; + + @Inject + @Optional + UISynchronize uiSynchronize; + + @Override + public int getLongOperationTime() { + return 800; + } + + @Override + public void registerIconForFamily(ImageDescriptor icon, Object family) { + String key = IMAGE_KEY + String.valueOf(imageKeyTable.size()); + imageKeyTable.put(family, key); + ImageRegistry registry = JFaceResources.getImageRegistry(); + + // Avoid registering twice + if (registry.getDescriptor(key) == null) { + registry.put(key, icon); + } + } + + @Override + public void runInUI(IRunnableContext context, + IRunnableWithProgress runnable, ISchedulingRule rule) + throws InvocationTargetException, InterruptedException { + final RunnableWithStatus runnableWithStatus = new RunnableWithStatus( + context, + runnable, rule); + uiSynchronize.syncExec(new Runnable() { + public void run() { + BusyIndicator.showWhile(getDisplay(), runnableWithStatus); + } + + }); + + IStatus status = runnableWithStatus.getStatus(); + if (!status.isOK()) { + Throwable exception = status.getException(); + if (exception instanceof InvocationTargetException) + throw (InvocationTargetException) exception; + else if (exception instanceof InterruptedException) + throw (InterruptedException) exception; + else // should be OperationCanceledException + throw new InterruptedException(exception.getMessage()); + } + } + + @Override + public Image getIconFor(Job job) { + Enumeration families = imageKeyTable.keys(); + while (families.hasMoreElements()) { + Object next = families.nextElement(); + if (job.belongsTo(next)) { + return JFaceResources.getImageRegistry().get( + (String) imageKeyTable.get(next)); + } + } + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ui.progress.IProgressService#busyCursorWhile(org.eclipse.jface.operation.IRunnableWithProgress) + */ + @Override + public void busyCursorWhile(final IRunnableWithProgress runnable) + throws InvocationTargetException, InterruptedException { + final ProgressMonitorJobsDialog dialog = new ProgressMonitorJobsDialog( + ProgressManagerUtil.getDefaultParent(), this, progressManager, + contentProviderFactory, finishedJobs); + dialog.setOpenOnRun(false); + final InvocationTargetException[] invokes = new InvocationTargetException[1]; + final InterruptedException[] interrupt = new InterruptedException[1]; + // show a busy cursor until the dialog opens + Runnable dialogWaitRunnable = new Runnable() { + public void run() { + try { + dialog.setOpenOnRun(false); + setUserInterfaceActive(false); + dialog.run(true, true, runnable); + } catch (InvocationTargetException e) { + invokes[0] = e; + } catch (InterruptedException e) { + interrupt[0] = e; + } finally { + setUserInterfaceActive(true); + } + } + }; + busyCursorWhile(dialogWaitRunnable, dialog); + if (invokes[0] != null) { + throw invokes[0]; + } + if (interrupt[0] != null) { + throw interrupt[0]; + } + } + + /* + * (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 { + if (fork == false || cancelable == false) { + // backward compatible code + final ProgressMonitorJobsDialog dialog = new ProgressMonitorJobsDialog( + null, this, progressManager, contentProviderFactory, + finishedJobs); + dialog.run(fork, cancelable, runnable); + return; + } + + busyCursorWhile(runnable); + } + + + /* + * (non-Javadoc) + * + * @see org.eclipse.ui.progress.IProgressService#showInDialog(org.eclipse.swt.widgets.Shell, + * org.eclipse.core.runtime.jobs.Job) + */ + @Override + public void showInDialog(Shell shell, Job job) { + if (shouldRunInBackground()) { + return; + } + + final ProgressMonitorFocusJobDialog dialog = new ProgressMonitorFocusJobDialog( + shell, this, progressManager, contentProviderFactory, + finishedJobs); + dialog.show(job, shell); + } + + /** + * Return whether or not dialogs should be run in the background + * + * @return <code>true</code> if the dialog should not be shown. + */ + protected boolean shouldRunInBackground() { + return Preferences.getBoolean(IProgressConstants.RUN_IN_BACKGROUND); + } + + private class RunnableWithStatus implements Runnable { + + IStatus status = Status.OK_STATUS; + private final IRunnableContext context; + private final IRunnableWithProgress runnable; + private final ISchedulingRule rule; + + public RunnableWithStatus(IRunnableContext context, + IRunnableWithProgress runnable, ISchedulingRule rule) { + this.context = context; + this.runnable = runnable; + this.rule = rule; + } + + public void run() { + IJobManager manager = Job.getJobManager(); + try { + manager.beginRule(rule, getEventLoopMonitor()); + context.run(false, false, runnable); + } catch (InvocationTargetException e) { + status = new Status(IStatus.ERROR, IProgressConstants.PLUGIN_ID, e + .getMessage(), e); + } catch (InterruptedException e) { + status = new Status(IStatus.ERROR, IProgressConstants.PLUGIN_ID, e + .getMessage(), e); + } catch (OperationCanceledException e) { + status = new Status(IStatus.ERROR, IProgressConstants.PLUGIN_ID, e + .getMessage(), e); + } finally { + manager.endRule(rule); + } + } + + /** + * Get a progress monitor that forwards to an event loop monitor. + * Override #setBlocked() so that we always open the blocked dialog. + * + * @return the monitor on the event loop + */ + private IProgressMonitor getEventLoopMonitor() { + + if (PlatformUI.isWorkbenchStarting()) + return new NullProgressMonitor(); + + return new EventLoopProgressMonitor(new NullProgressMonitor()) { + + public void setBlocked(IStatus reason) { + + // Set a shell to open with as we want to create + // this + // even if there is a modal shell. + Dialog.getBlockedHandler().showBlocked( + ProgressManagerUtil.getDefaultParent(), this, + reason, getTaskName()); + } + }; + } + + public IStatus getStatus() { + return status; + } + + } + + /** + * Show the busy cursor while the runnable is running. Schedule a job to + * replace it with a progress dialog. + * + * @param dialogWaitRunnable + * @param dialog + */ + private void busyCursorWhile(Runnable dialogWaitRunnable, + ProgressMonitorJobsDialog dialog) { + // create the job that will open the dialog after a delay + scheduleProgressMonitorJob(dialog); + final Display display = getDisplay(); + if (display == null) { + return; + } + // show a busy cursor until the dialog opens + BusyIndicator.showWhile(display, dialogWaitRunnable); + } + + /** + * Schedule the job that will open the progress monitor dialog + * + * @param dialog + * the dialog to open + */ + private void scheduleProgressMonitorJob( + final ProgressMonitorJobsDialog dialog) { + + final Job updateJob = new UIJob( + ProgressMessages.ProgressManager_openJobName) { + /* + * (non-Javadoc) + * + * @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor) + */ + public IStatus runInUIThread(IProgressMonitor monitor) { + setUserInterfaceActive(true); + if (ProgressManagerUtil.safeToOpen(dialog, null)) { + dialog.open(); + } + return Status.OK_STATUS; + } + }; + updateJob.setSystem(true); + updateJob.schedule(getLongOperationTime()); + + } + + /** + * Iterate through all of the windows and set them to be disabled or enabled + * as appropriate.' + * + * @param active + * The set the windows will be set to. + */ + private void setUserInterfaceActive(boolean active) { + Shell[] shells = getDisplay().getShells(); + if (active) { + for (int i = 0; i < shells.length; i++) { + if (!shells[i].isDisposed()) { + shells[i].setEnabled(active); + } + } + } else { + // Deactive shells in reverse order + for (int i = shells.length - 1; i >= 0; i--) { + if (!shells[i].isDisposed()) { + shells[i].setEnabled(active); + } + } + } + } + + protected Display getDisplay() { + return Services.getInstance().getDisplay(); + } + +} |