Package com.cedarsoft.spring.rcp.async

Source Code of com.cedarsoft.spring.rcp.async.BlockingBackgroundActionRunner

package com.cedarsoft.spring.rcp.async;

import com.cedarsoft.CanceledException;
import com.cedarsoft.SwingHelper;
import com.cedarsoft.spring.SpringSupport;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.springframework.richclient.application.ApplicationWindow;
import org.springframework.richclient.application.splash.InfiniteProgressPanel;

import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
* Supports running tasks in background - but blocks the UI
*/
public final class BlockingBackgroundActionRunner implements Runnable {
  @NotNull
  private final InfiniteProgressPanel progressPanel = new InfiniteProgressPanel();
  @NotNull
  private final ApplicationWindow applicationWindow;
  @NotNull
  private final BackgroundAction action;

  /**
   * The delay before the progress is shown
   */
  private final int delay;

  /**
   * Creates a new blocking background runner
   *
   * @param applicationWindow the applicationn window that is blocked
   * @param action            the background action that is executed
   */
  public BlockingBackgroundActionRunner( @NotNull ApplicationWindow applicationWindow, @NotNull BackgroundAction action ) {
    this( applicationWindow, action, true );
  }

  /**
   * Creates a new blocking background runner
   *
   * @param applicationWindow the application window
   * @param action            the background action that is executed
   * @param delay             whether there should be used a delay
   */
  public BlockingBackgroundActionRunner( @NotNull ApplicationWindow applicationWindow, @NotNull BackgroundAction action, boolean delay ) {
    this.action = action;
    this.applicationWindow = applicationWindow;
    if ( delay ) {
      this.delay = 1000;
    } else {
      this.delay = 0;
    }
  }

  @NotNull
  private final Lock lock = new ReentrantLock();

  @NotNull
  private final ReadWriteLock activeLock = new ReentrantReadWriteLock();

  private boolean active;

  /**
   * Starts the blocking background runner.
   * This method must be called from the EDT
   */
  @Override
  public void run() {
    if ( !SwingHelper.isEventDispatchThread() ) {
      SwingUtilities.invokeLater( this );
      return;
    }

    SwingHelper.assertEventThread();
    if ( !action.confirm() ) {
      return;
    }

    action.prepare();

    //Show the progress after the given delay (if set)
    if ( delay > 0 ) {
      Timer timer = new Timer( delay, new ActionListener() {
        @Override
        public void actionPerformed( ActionEvent e ) {
          if ( isActive() ) {
            showProgress();
          }
        }
      } );
      timer.setRepeats( false );
      timer.start();
    } else {
      showProgress();
    }

    new Thread( new Runnable() {
      @Override
      public void run() {
        try {
          try {
            setActive( true );
            action.executeInBackground();
            setActive( false );
            SwingUtilities.invokeLater( new Runnable() {
              @Override
              public void run() {
                action.finished();
              }
            } );
          } catch ( CanceledException ignore ) {
          } catch ( Exception e ) {
            throw new RuntimeException( e );
          }
        } finally {
          setActive( false );
          hideProgress();
        }
      }
    } ).start();
  }

  private void setActive( final boolean active ) {
    activeLock.writeLock().lock();
    try {
      this.active = active;
    } finally {
      activeLock.writeLock().unlock();
    }
  }

  @SuppressWarnings( {"MethodOnlyUsedFromInnerClass"} )
  private boolean isActive() {
    activeLock.readLock().lock();
    try {
      return active;
    } finally {
      activeLock.readLock().unlock();
    }
  }

  private Component oldGlassPane;

  void hideProgress() {
    setActive( false );
    SwingUtilities.invokeLater( new Runnable() {
      @Override
      public void run() {
        lock.lock();
        try {
          if ( oldGlassPane == null ) {
            return;
          }
          getApplicationWindow().getControl().setGlassPane( oldGlassPane );
        } finally {
          progressPanel.stop();
          progressPanel.interrupt();
          lock.unlock();
        }
      }
    } );
  }

  @SuppressWarnings( {"MethodOnlyUsedFromInnerClass"} )
  private void showProgress() {
    lock.lock();
    try {
      setProgressMessage( action.getInitialProgressMessageKey() );
      //Now store the old glass pane
      oldGlassPane = getApplicationWindow().getControl().getGlassPane();
      getApplicationWindow().getControl().setGlassPane( progressPanel );
      getApplicationWindow().getControl().validate();
      progressPanel.start();
    } finally {
      lock.unlock();
    }
  }

  @NotNull
  JFrame getParentWindowControl() {
    return getApplicationWindow().getControl();
  }

  /**
   * Updates the progress panel with the given message
   *
   * @param key     the key for the message
   * @param objects the objects
   */
  public void setProgressMessage( @NotNull @NonNls String key, @NotNull Object... objects ) {
    progressPanel.setText( SpringSupport.INSTANCE.getMessage( key, objects ) );
  }

  @NotNull
  public ApplicationWindow getApplicationWindow() {
    return applicationWindow;
  }
}
TOP

Related Classes of com.cedarsoft.spring.rcp.async.BlockingBackgroundActionRunner

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.