gt: 		while ( !shell.isDisposed() ) {
context: package com.kartoflane.superluminal2.ui;
  
  import org.eclipse.swt.SWT;
  import org.eclipse.swt.events.SelectionAdapter;
  import org.eclipse.swt.events.SelectionEvent;
  import org.eclipse.swt.graphics.Point;
  import org.eclipse.swt.layout.FillLayout;
  import org.eclipse.swt.layout.GridData;
  import org.eclipse.swt.layout.GridLayout;
  import org.eclipse.swt.widgets.Button;
  import org.eclipse.swt.widgets.Composite;
  import org.eclipse.swt.widgets.Display;
  import org.eclipse.swt.widgets.Event;
  import org.eclipse.swt.widgets.Listener;
  import org.eclipse.swt.widgets.ProgressBar;
  import org.eclipse.swt.widgets.Shell;
  import org.eclipse.swt.widgets.Text;
  
  import com.kartoflane.common.selfpatch.SPDownloadWindow;
  import com.kartoflane.superluminal2.Superluminal;
  
  
  public class DownloadDialog implements SPDownloadWindow
  {
  	private static DownloadDialog instance = null;
  
  	private Shell shell = null;
  	private Composite barHolder = null;
  	private ProgressBar barProgress = null;
  	private Text txtStatus = null;
  	private Button btnContinue = null;
  
  	private Thread taskThread = null;
  
  	private boolean progressIndeterminate = false;
  	private boolean done = false;
  	private boolean succeeded = false;
  
  
  	public DownloadDialog( Shell parent )
  	{
  		if ( instance != null )
  			throw new IllegalStateException( "Previous instance has not been disposed!" );
  		instance = this;
  
  		shell = new Shell( parent, SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL );
  		shell.setText( Superluminal.APP_NAME + " - Downloading" );
  		GridLayout gl_shell = new GridLayout( 1, false );
  		shell.setLayout( gl_shell );
  
  		barHolder = new Composite( shell, SWT.NONE );
  		barHolder.setLayoutData( new GridData( SWT.FILL, SWT.CENTER, true, false, 1, 1 ) );
  		barHolder.setLayout( new FillLayout( SWT.HORIZONTAL ) );
  
  		barProgress = new ProgressBar( barHolder, SWT.SMOOTH );
  
  		txtStatus = new Text( shell, SWT.BORDER );
  		txtStatus.setLayoutData( new GridData( SWT.FILL, SWT.FILL, true, true, 1, 1 ) );
  		txtStatus.setEditable( false );
  
  		btnContinue = new Button( shell, SWT.NONE );
  		GridData gd_btnContinue = new GridData( SWT.CENTER, SWT.CENTER, true, false, 1, 1 );
  		gd_btnContinue.widthHint = 80;
  		btnContinue.setLayoutData( gd_btnContinue );
  		btnContinue.setText( "Continue" );
  		btnContinue.setEnabled( false );
  
  		shell.setSize( 400, 140 );
  		Point size = shell.getSize();
  		shell.setSize( size.x + 5, size.y );
  		Point parSize = parent.getSize();
  		Point parLoc = parent.getLocation();
  		shell.setLocation( parLoc.x + parSize.x / 2 - size.x / 2, parLoc.y + parSize.y / 3 - size.y / 2 );
  
  		btnContinue.addSelectionListener(
  			new SelectionAdapter() {
  				@Override
  				public void widgetSelected( SelectionEvent e )
  				{
  					dispose();
  				}
  			}
  		);
  
  		shell.addListener(
  			SWT.Close, new Listener() {
  				@Override
  				public void handleEvent( Event e )
  				{
  					e.doit = false;
  					dispose();
  				}
  			}
  		);
  	}
  
  	private void setIndeterminate( boolean indeterminate )
  	{
  		progressIndeterminate = indeterminate;
  		if ( barProgress != null && !barProgress.isDisposed() )
  			barProgress.dispose();
  		barProgress = new ProgressBar( barHolder, SWT.SMOOTH | ( indeterminate ? SWT.INDETERMINATE : SWT.NONE ) );
  	}
  
  
  	/**
  	 * Updates the text area's content. (Thread-safe)
  	 *
  	 * @param message
  	 *            a string, or null
  	 */
  	public void setStatusTextLater( final String message )
  	{
  		shell.getDisplay().asyncExec(
  			new Runnable() {
  				public void run()
  				{
  					setStatusText( message != null ? message : "..." );
  				}
  			}
  		);
  	}
  
  	protected void setStatusText( String message )
  	{
  		txtStatus.setText( message != null ? message : "..." );
  	}
  
  	/**
  	 * Updates the progress bar. (Thread-safe)
  	 *
  	 * If the arg is -1, the bar will become indeterminate.
  	 *
  	 * @param value
  	 *            the new value
  	 */
  	public void setProgressLater( final int value )
  	{
  		shell.getDisplay().asyncExec(
  			new Runnable() {
  				@Override
  				public void run()
  				{
  					if ( value >= 0 ) {
  						if ( progressIndeterminate )
  							setIndeterminate( false );
  						barProgress.setSelection( value );
  					}
  					else {
  						if ( !progressIndeterminate )
  							setIndeterminate( true );
  						barProgress.setSelection( 0 );
  					}
  				}
  			}
  		);
  	}
  
  	/**
  	 * Updates the progress bar. (Thread-safe)
  	 *
  	 * If either arg is -1, the bar will become indeterminate.
  	 *
  	 * @param value
  	 *            the new value
  	 * @param max
  	 *            the new maximum
  	 */
  	public void setProgressLater( final int value, final int max )
  	{
  		shell.getDisplay().asyncExec(
  			new Runnable() {
  				@Override
  				public void run()
  				{
  					if ( value >= 0 && max >= 0 ) {
  						if ( progressIndeterminate )
  							setIndeterminate( false );
  
  						if ( barProgress.getMaximum() != max ) {
  							barProgress.setSelection( 0 );
  							barProgress.setMaximum( max );
  						}
  						barProgress.setSelection( value );
  					}
  					else {
  						if ( !progressIndeterminate )
  							setIndeterminate( true );
  						barProgress.setSelection( 0 );
  					}
  				}
  			}
  		);
  	}
  
  	/**
  	 * Triggers a response to the immediate task ending. (Thread-safe)
  	 *
  	 * If anything went wrong, e may be non-null.
  	 */
  	public void setTaskOutcomeLater( final boolean success, final Exception e )
  	{
  		shell.getDisplay().asyncExec(
  			new Runnable() {
  				@Override
  				public void run()
  				{
  					setTaskOutcome( success, e );
  				}
  			}
  		);
  	}
  
  	protected void setTaskOutcome( final boolean outcome, final Exception e )
  	{
  		done = true;
  		succeeded = outcome;
  
  		if ( !shell.isVisible() ) {
  			// The window's not visible, no continueBtn to click.
  			dispose();
  		}
  
  		btnContinue.setEnabled( true );
  		btnContinue.setFocus();
  	}
  
  	@Override
  	public void taskProgress( int value, int max )
  	{
  		this.setProgressLater( value, max );
  	}
  
  	@Override
  	public void taskStatus( String message )
  	{
  		setStatusTextLater( message != null ? message : "..." );
  	}
  
  	@Override
  	public void taskFinished( boolean outcome, Exception e )
  	{
  		setTaskOutcomeLater( outcome, e );
  	}
  
  	@Override
  	public void spShow()
  	{
  		shell.open();
  
  		Display display = shell.getDisplay();
  