All Downloads are FREE. Search and download functionalities are using the official Maven repository.

at.spardat.xma.rpc.BusyExecutor Maven / Gradle / Ivy

There is a newer version: 6.0.2
Show newest version
package at.spardat.xma.rpc;

import java.io.IOException;
import java.io.InputStream;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageLoader;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

import at.spardat.xma.page.DialogPage;

abstract public class BusyExecutor {

    private Display display;
    private Shell shell;
    private Canvas canvas;

    private static ImageLoader loader;
    private int imageNumber = 0;

    private final Object semaphor = new Object();

    abstract public Object execute() throws Exception;

    private Exception exception;
    private Object result;

    private long lastDraw = 0;

    /**
     * Load the animated image
     *
     * @throws IOException
     */
    protected void loadImage() {
        if (loader == null) {
            loader = new ImageLoader();
            InputStream is = BusyExecutor.class.getClassLoader().getResourceAsStream("at/spardat/xma/rpc/active-communication.gif");
            try {
                loader.load(is);
            } finally {
                if (is != null) {
                    try {
                        is.close();
                    } catch (Exception ex) {
                        throw new RuntimeException("Can not close image loader", ex);
                    }
                }
            }
        }
    }

    /**
     * Start the execution of the job.
     * 

* Exceptions happening in execute() will be stored in the field * exception, and can be queried with getException(). No exception * is thrown here. *

* The result of the execute method can later be retrieved by * getResult(). * * @return The result of the execute method */ public Object startExecutor() { display = BusyExecutorHelper.getDisplay(); BusyIndicator.showWhile(display, new Runnable() { public void run() { try { // Execute job and show busy indicator ExcuteThread executeThread = new ExcuteThread(); Shell activeShell = null; // Show animation after a while synchronized (semaphor) { executeThread.start(); if (display != null) { activeShell = display.getActiveShell(); } semaphor.wait(2000); if (executeThread.running) { if (activeShell != null) { shell = new Shell(activeShell, SWT.APPLICATION_MODAL | SWT.BORDER); } else { shell = new Shell(display, SWT.APPLICATION_MODAL | SWT.BORDER); } } } if (shell != null) { showBusyShell(activeShell, executeThread); } setResult(executeThread.getResult()); setException(executeThread.getException()); } catch (InterruptedException e) { // Sleep interrupted } } }); return getResult(); } protected void showBusyShell(Shell parentShell, ExcuteThread executeThread) { loadImage(); shell.setLayout(new FillLayout()); canvas = new Canvas(shell, SWT.NONE); canvas.addPaintListener(new PaintListener() { public void paintControl(PaintEvent event) { Image image = new Image(display, loader.data[imageNumber]); event.gc.drawImage(image, 0, 0); image.dispose(); } }); /* Open the shell and start the animation */ shell.pack(); //shell.layout(); DialogPage.centerShell(parentShell, shell); shell.open(); new AnimationThread().start(); BusyIndicator.showWhile(display, new Runnable() { public void run() { while (!shell.isDisposed()) { // animate every 200ms at maximum. if (System.currentTimeMillis() - lastDraw > 200) { imageNumber = imageNumber == loader.data.length - 1 ? 0 : imageNumber + 1; canvas.redraw(); lastDraw = System.currentTimeMillis(); } if (BusyExecutorHelper.hasDisplayMessages()) { // dispose and breake if there is an SWT runnable // in order to not break XMA conventions. shell.dispose(); break; } // this here is small gap in the solution: // when between the check and readAndDispatch() someone schedules a task // it will be executed in readAndDispatch() agains our will. if (!display.readAndDispatch()) { display.sleep(); } } } }); // check if we are really ready. This is necessary because of the early breaks above synchronized (semaphor) { while (executeThread.running) { try { semaphor.wait(100); } catch(InterruptedException e) { e.printStackTrace(); } } } } public Exception getException() { return exception; } private void setException(Exception exception) { this.exception = exception; } public Object getResult() { return result; } private void setResult(Object result) { this.result = result; } private class ExcuteThread extends Thread { private boolean running = true; private Exception exception; private Object result; public void run() { try { result = execute(); } catch (Exception e) { exception = e; } finally { synchronized (semaphor) { running = false; semaphor.notifyAll(); } display.syncExec(new Runnable() { // NOTE: this asynchexec already stops the event loop public void run() { if (shell != null) { shell.dispose(); // ... this is thus only to make it sure. display.wake(); } } }); } } public Exception getException() { return exception; } public Object getResult() { return result; } } class AnimationThread extends Thread { public void run() { while (!shell.isDisposed()) { display.wake(); // animate in the main event loop, only trigger a wake here try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy