//(c) Copyright 2005, Scott Vorthmann. All rights reserved.
package org.vorthmann.ui;
import java.awt.Component;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* An Action that is time-consuming and must not occur on the event-handling thread.
* Only one such action may be started at once, and it can be canceled before completion.
*
* @author Scott Vorthmann
*
*/
public abstract class ExclusiveAction implements ActionListener
{
public static class Excluder
{
private final List<Component> mListeners = new ArrayList<>(40);
private final PropertyChangeListener statusListener;
private boolean busy = false;
public Excluder( PropertyChangeListener statusListener )
{
this.statusListener = statusListener;
}
public boolean isBusy()
{
return this.busy;
}
public void grab( SwingWorker worker )
{
grab();
worker .start();
}
public void grab()
{
this .busy = true;
for (Component listener : mListeners) {
listener .setEnabled( false );
}
}
public void release()
{
for (Component listener : mListeners) {
listener .setEnabled( true );
}
this .statusListener .propertyChange( new PropertyChangeEvent( this, "command.status", "busy...", "" ) );
this .busy = false;
}
//
// private void setEnabled( Component object, boolean value )
// {
// try {
// Class clazz = object .getClass();
// Method method = clazz .getMethod( "setEnabled", new Class[]{ Boolean.TYPE } );
// method .invoke( object, new Object[]{ new Boolean( value ) } );
// } catch ( Exception e ) {
// throw new RuntimeException( e );
// }
// }
public void addExcludable( Component component )
{
// disabling this behavior, in favor of a simple "beep" action when another ExclusiveAction is in progress
// if ( component .isEnabled() )
// mListeners .add( component );
}
public void reportBusy()
{
this .statusListener .propertyChange( new PropertyChangeEvent( this, "command.status", "", "busy..." ) );
}
}
private final Excluder mExcluder;
private static final Logger logger = Logger .getLogger( "org.vorthmann.ui.background" );
public ExclusiveAction( Excluder excluder )
{
super();
mExcluder = excluder;
}
@Override
public void actionPerformed( final ActionEvent e )
{
if ( this .mExcluder .isBusy() ) {
this .mExcluder .reportBusy();
Toolkit .getDefaultToolkit() .beep();
return;
}
final SwingWorker worker = new SwingWorker()
{
@Override
public Object construct()
{
try {
doAction( e );
return null;
} catch ( Exception e ) {
logger .log( Level.INFO, e .getMessage(), e );
return e;
}
}
@Override
public void finished()
{
Object error = get();
if ( error != null )
showError( (Exception) error );
mExcluder .release();
}
};
mExcluder .grab( worker );
}
protected abstract void doAction( ActionEvent e ) throws Exception;
protected abstract void showError( Exception e );
}