org.eclipse.e4.ui.progress.internal.ProgressServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.e4.ui.progress.internal.ProgressServiceImpl.java

Source

/*******************************************************************************
 * Copyright (c) 2010, 2015 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
 *     Philipp Bumann <bumannp@gmail.com> - Bug 477602
 ******************************************************************************/

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<Object, String> 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() {
            @Override
            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<Object> families = imageKeyTable.keys();
        while (families.hasMoreElements()) {
            Object next = families.nextElement();
            if (job.belongsTo(next)) {
                return JFaceResources.getImageRegistry().get(imageKeyTable.get(next));
            }
        }
        return null;
    }

    @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() {
            @Override
            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];
        }
    }

    @Override
    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);
    }

    @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;
        }

        @Override
        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()) {

                @Override
                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) {
            @Override
            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();
    }

}