Package org.locationtech.udig.ui

Source Code of org.locationtech.udig.ui.PlatformGIS$RunnableAndProgress

/*
*    uDig - User Friendly Desktop Internet GIS client
*    http://udig.refractions.net
*    (C) 2004, Refractions Research Inc.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD
* License v1.0 (http://udig.refractions.net/files/bsd3-v10.html).
*
*/
package org.locationtech.udig.ui;

import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;

import org.locationtech.udig.aoi.IAOIService;
import org.locationtech.udig.internal.ui.UiPlugin;
import org.locationtech.udig.ui.internal.Messages;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.services.ServiceLocator;
import org.eclipse.ui.internal.services.WorkbenchServiceRegistry;
import org.geotools.brewer.color.ColorBrewer;

/**
* A facade into udig to simplify operations relating to performing platform operations.
*
* @author jeichar
* @since 1.1
* @version 1.2.3
*/
public class PlatformGIS {

    private static ColorBrewer colorBrewer;
    private static ExecutorService executor = Executors.newCachedThreadPool();

    /**
     * Runs the given runnable in a separate thread, providing it a progress monitor. Exceptions
     * thrown by the runnable are logged, and not rethrown.
     */
    public static void run( IRunnableWithProgress request ) {
        Runner runner = new Runner();
        runner.setRequest(request);
        runner.schedule();
    }
    /**
     * Runs the given runnable in a separate thread, providing it a progress monitor. Exceptions
     * thrown by the runnable are logged, and not rethrown.
     */
    public static void run( IRunnableWithProgress request, IProgressMonitor monitorToUse) {
        Runner runner = new Runner();
        RunnableAndProgress runnable = new RunnableAndProgress(request, monitorToUse);
        runner.setRequest(runnable);
        runner.schedule();
       
    }

    /**
     * This method runs the runnable in a separate thread. It is useful in cases where a thread must
     * wait for a long running and potentially blocking operation (for example an IO operation). If
     * the IO is done in the UI thread then the user interface will lock up. This allows synchronous
     * execution of a long running thread in the UI thread without locking the UI.
     * <p>
     * When called from the display thread, a {@link #executor} is used to schedule the background
     * runnable, and we will take over the {@link Display#readAndDispatch()} cycle while waiting
     * for the background runable to complete. When completed normal display thread execution will
     * resume.
     *
     * @param runnable The runnable(operation) to run
     * @param monitor the progress monitor to update.
     * @throws InvocationTargetException
     * @throws InterruptedException
     */
    public static void runBlockingOperation( final IRunnableWithProgress runnable,
            final IProgressMonitor monitor2 ) throws InvocationTargetException, InterruptedException {

        final IProgressMonitor monitor=monitor2==null?new NullProgressMonitor():monitor2;
        final InterruptedException[] interruptedException = new InterruptedException[1];
        final InvocationTargetException[] invocationTargetException = new InvocationTargetException[1];
        Display d = Display.getCurrent();
        if (d == null)
            d = Display.getDefault();
        final Display display = d;
        final AtomicBoolean done = new AtomicBoolean();
        final Object mutex=new Object();
        done.set(false);

        Future<Object> future = executor.submit(new Callable<Object>(){
            @SuppressWarnings("unused")
            Exception e = new Exception("For debugging"); //$NON-NLS-1$
            public Object call() throws Exception {
                try {
                    runnable.run(new OffThreadProgressMonitor(monitor != null
                            ? monitor
                            : ProgressManager.instance().get(), display));
                } catch (InvocationTargetException ite) {
                    invocationTargetException[0] = ite;
                } catch (InterruptedException ie) {
                    interruptedException[0] = ie;
                } finally {
                    done.set(true);
                    synchronized (mutex) {
                        mutex.notify();
                    }
                }
                return null;
            }

        });
        while( !monitor.isCanceled() && !done.get() && !Thread.interrupted() ) {
            Thread.yield();
            if (Display.getCurrent() == null) {
                wait(mutex, 200);
            } else {
                try {
                    if (!d.readAndDispatch()) {
                        wait(mutex, 200);
                    }
                } catch (Exception e) {
                    UiPlugin.log("Error occurred while waiting for an operation to complete", e); //$NON-NLS-1$
                }
            }
        }
        if (monitor.isCanceled()) {
            future.cancel(true);
        }

        if (interruptedException[0] != null)
            throw interruptedException[0];
        else if (invocationTargetException[0] != null)
            throw invocationTargetException[0];
    }

    private static void wait( Object mutex, long waitTime ) {
        synchronized (mutex) {
            try {
                mutex.wait(waitTime);
            } catch (InterruptedException e) {
                return ;
            }
        }
    }

    /**
     * Runs the given runnable in a protected mode. Exceptions thrown in the runnable are logged and
     * passed to the runnable's exception handler. Such exceptions are not rethrown by this method.
     */
    public static void run( ISafeRunnable request ) {
        Runner runner = new Runner();
        runner.setRequest(request);
        runner.schedule();
    }

    private static class Runner extends Job {

        public Runner( ) {
            super("Platform GIS runner"); //$NON-NLS-1$
        }

        Object runnable;

        /**
         * Add a runnable object to be run.
         *
         * @param runnable
         */
        public void setRequest( Object runnable ) {
            this.runnable = runnable;
        }

        private void run( ISafeRunnable runnable ) {
            try {
                runnable.run();
            } catch (Throwable e) {
                if (e.getMessage() != null) {
                    UiPlugin.log(e.getMessage(), e);
                } else {
                    UiPlugin.log("", e); //$NON-NLS-1$
                }
                runnable.handleException(e);
            }
        }

        private void run( IRunnableWithProgress runnable, IProgressMonitor monitor ) {
            try {
                runnable.run(monitor);
            } catch (Throwable t) {
                UiPlugin.log("", t); //$NON-NLS-1$
            }
        }

        @Override
        protected IStatus run( IProgressMonitor monitor ) {  
            if (!PlatformUI.getWorkbench().isClosing()) {
                if (runnable != null) {
   
                    if (runnable instanceof ISafeRunnable) {
                        run((ISafeRunnable) runnable);
                    } else if (runnable instanceof IRunnableWithProgress) {
                        run((IRunnableWithProgress) runnable, monitor);
                    }else if (runnable instanceof RunnableAndProgress) {
                        RunnableAndProgress request = (RunnableAndProgress)runnable;
                        run(request.runnable, request.monitor);
                    }
                }
            }
            return Status.OK_STATUS;
        }
    }

    private static class RunnableAndProgress{
        public RunnableAndProgress( IRunnableWithProgress request, IProgressMonitor monitorToUse ) {
            this.runnable=request;
            Display display = Display.getCurrent();
            if( display == null ){
                Display.getDefault();
            }
            this.monitor = new OffThreadProgressMonitor(monitorToUse, display);
        }
        IRunnableWithProgress runnable;
        IProgressMonitor monitor;
    }
   
    public static ColorBrewer getColorBrewer() {
        synchronized (ColorBrewer.class) {
            if (colorBrewer == null) {
                colorBrewer = ColorBrewer.instance();
            }
        }
        return colorBrewer;
    }

    /**
     * Acts as a safer alternative to Display.syncExec(). If readAndDispatch is being called from
     * the display thread syncExec calls will not be executed only Display.asyncExec calls are
     * executed. So this method uses Display.asyncExec and patiently waits for the result to be
     * returned. Can be called from display thread or non-display thread. Runnable should not be
     * blocking or it will block the display thread.
     *
     * @param runnable runnable to execute
     */
    public static void syncInDisplayThread( final Runnable runnable ) {
        Display display = Display.getCurrent();
        if( display==null ){
            display = Display.getDefault();
        }
        syncInDisplayThread(display, runnable);
    }
    /**
     * Run in the display thread at the next reasonable opportunity, current thread will
     * wait for the runnable to complete.
     *
     * @param display
     * @param runnable
     */
    public static void syncInDisplayThread( Display display, final Runnable runnable ) {
        if (Display.getCurrent() != display) {
            final AtomicBoolean done = new AtomicBoolean(false);
            final Object mutex=new Object();
            display.asyncExec(new Runnable(){
                public void run() {
                    try {
                        runnable.run();
                    } finally {
                        done.set(true);
                        synchronized (mutex) {
                            mutex.notify();
                        }
                    }
                }
            });
            while( !done.get() && !Thread.interrupted() ) {
                synchronized (mutex) {
                    wait(mutex, 200);
                }
            }
        } else {
            runnable.run();
        }
    }

    /**
     * Waits for the condition to become true. Will call Display#readAndDispatch() if currently in
     * the display thread.
     *
     * @param interval the time to wait between testing of condition, in milliseconds. Must be a
     *        positive number and is recommended to be larger than 50
     * @param timeout maximum time to wait. Will throw an {@link InterruptedException} if reached.
     *        If -1 then it will not timeout.
     * @param condition condition to wait on.
     * @param mutex if not null mutex will be waited on so that a notify will interrupt the wait.
     * @throws InterruptedException
     */
    public static void wait( long interval, long timeout, WaitCondition condition, Object mutex )
            throws InterruptedException {
        long start = System.currentTimeMillis();
        Object mutex2 = mutex == null ? new Object() : mutex;

        Display current = Display.getCurrent();
        if (current == null) {
            while( !condition.isTrue() ) {
                if (timeout > 0 && System.currentTimeMillis() - start > timeout)
                    throw new InterruptedException("Timed out waiting for condition " + condition); //$NON-NLS-1$
                synchronized (mutex2) {
                    mutex2.wait(interval);
                }
            }
        } else {
            while( !condition.isTrue() ) {
                Thread.yield();
                if (timeout > 0 && System.currentTimeMillis() - start > timeout)
                    throw new InterruptedException("Timed out waiting for condition " + condition); //$NON-NLS-1$
                if (!current.readAndDispatch())
                    synchronized (mutex2) {
                        mutex2.wait(interval);
                    }
            }

        }
    }

    /**
     * Runs a blocking task in a ProgressDialog. It is ran in such a way that even if the task
     * blocks it can be cancelled. This is unlike the normal ProgressDialog.run(...) method which
     * requires that the {@link IProgressMonitor} be checked and the task to "nicely" cancel.
     *
     * @param dialogTitle The title of the Progress dialog
     * @param showRunInBackground if true a button added to the dialog that will make the job be ran
     *        in the background.
     * @param runnable the task to execute.
     * @param runASync if true the runnable will be ran asynchronously
     */
    public static void runInProgressDialog( final String dialogTitle,
            final boolean showRunInBackground, final IRunnableWithProgress runnable,
            boolean runASync ) {

        Runnable object = new Runnable(){
            public void run() {
                Shell shell = Display.getDefault().getActiveShell();
                ProgressMonitorDialog dialog = new ProgressMonitorDialog(shell){
                    @Override
                    protected void configureShell( Shell shell ) {
                        super.configureShell(shell);
                        shell.setText(dialogTitle);
                    }

                    @Override
                    protected void createButtonsForButtonBar( Composite parent ) {
                        if (showRunInBackground)
                            createBackgroundButton(parent);
                        super.createButtonsForButtonBar(parent);
                    }

                    private void createBackgroundButton( Composite parent ) {
                        createButton(parent, IDialogConstants.BACK_ID,
                                Messages.PlatformGIS_background, true);
                    }

                    @Override
                    protected void buttonPressed( int buttonId ) {
                        if (buttonId == IDialogConstants.BACK_ID) {
                            getShell().setVisible(false);
                        } else
                            super.buttonPressed(buttonId);
                    }
                };
                try {

                    dialog.run(true, true, new IRunnableWithProgress(){
                        public void run( IProgressMonitor monitor ) {
                            try {
                                runBlockingOperation(new IRunnableWithProgress(){

                                    public void run( IProgressMonitor monitor )
                                            throws InvocationTargetException, InterruptedException {
                                        runnable.run(monitor);
                                    }
                                }, monitor);
                            } catch (Exception e) {
                                UiPlugin.log("", e); //$NON-NLS-1$
                            }

                        }
                    });
                } catch (Exception e) {
                    UiPlugin.log("", e); //$NON-NLS-1$
                }
            }
        };

        if (runASync)
            Display.getDefault().asyncExec(object);
        else
            syncInDisplayThread(object);
    }

    /**
     * Runs the runnable in the display thread but asynchronously.
     *
     * @param runnable the runnable to execute
     * @param executeIfInDisplay if true and the current thread is the display thread then the
     *        runnable will just be executed.
     */
    public static void asyncInDisplayThread( Runnable runnable, boolean executeIfInDisplay ) {
        Display display = Display.getCurrent();
        if (display == null) {
            display = Display.getDefault();
        }
        asyncInDisplayThread(display, runnable, executeIfInDisplay);
    }

    /**
     * Runs the runnable in the display thread but asynchronously.
     *
     * @param display the display in which to run the runnable
     * @param runnable the runnable to execute
     * @param executeIfInDisplay if true and the current thread is the display thread then the
     *        runnable will just be executed.
     */
    public static void asyncInDisplayThread( Display display, Runnable runnable,
            boolean executeIfInDisplay ) {
        if (executeIfInDisplay && display == Display.getCurrent()) {
            runnable.run();
        } else {
            display.asyncExec(runnable);
        }
    }
   
    /**
     * Gets the Area of Interest workbench service
     * @return
     */
    public static IAOIService getAOIService() {
        IWorkbench workbench = PlatformUI.getWorkbench();
        return (IAOIService) workbench.getService(IAOIService.class);
    }
   
}
TOP

Related Classes of org.locationtech.udig.ui.PlatformGIS$RunnableAndProgress

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.