package edu.harvard.wcfia.yoshikoder.util;
import java.awt.Component;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.SwingUtilities;
/**
* This is a variant of the SwingWorker It works in conjunction with the
* GlassPane class to allow users to execute time consuming task on a separate
* thread The GlassPane addition can prevent users from executing another
* SwingWorker task while one SwingWorker task is already executing
*
* @author Yexin Chen
*/
public abstract class SwingWorkerVariant {
private static Logger log =
Logger.getLogger("edu.harvard.wcfia.yoshikoder.util.SwingWorkerVariant");
/**
* Class to maintain reference to current worker thread under separate
* synchronization control.
*/
private static class ThreadVar {
private Thread thread;
ThreadVar(Thread t) {
thread = t;
}
synchronized Thread get() {
return thread;
}
synchronized void clear() {
thread = null;
}
}
ThreadVar threadVar;
private GlassPane glassPane;
private java.awt.Component aComponent;
/**
* Start a thread that will call the <code>construct</code> method and
* then exit.
*
* @param aComponent
* a reference to the UI component that's directly using
* SwingWorker
*/
public SwingWorkerVariant(Component aComponent) {
setAComponent(aComponent);
final Runnable doFinished = new Runnable() {
public void run() {
finished();
}
};
Runnable doConstruct = new Runnable() {
public void run() {
try {
construct();
} finally {
threadVar.clear();
}
// Execute the doFinished runnable on the Swing dispatcher
// thread
SwingUtilities.invokeLater(doFinished);
}
};
// Group the new worker thread in the same group as the "spawner" thread
Thread t = new Thread(Thread.currentThread().getThreadGroup(),
doConstruct);
threadVar = new ThreadVar(t);
}
/**
* Activate the capabilities of glasspane
*
*/
private void activateGlassPane() {
// Mount the glasspane on the component window
GlassPane aPane = GlassPane.mount(getAComponent(), true);
// keep track of the glasspane as an instance variable
setGlassPane(aPane);
if (getGlassPane() != null) {
// Start interception UI interactions
getGlassPane().setVisible(true);
}
}
/**
* Enable the glass pane (to disable unwanted UI manipulation), then spawn
* the non-UI logic on a separate thread.
*/
void construct() {
activateGlassPane();
try {
doNonUILogic();
} catch (RuntimeException e) {
}
}
/**
* Deactivate the glasspane
*
*/
private void deactivateGlassPane() {
if (getGlassPane() != null) {
// Stop UI interception
getGlassPane().setVisible(false);
}
}
/**
* This method will be implemented by the inner class of SwingWorker It
* should only consist of the logic that's unrelated to UI
*
* @throws java.lang.RuntimeException
* thrown if there are any errors in the non-ui logic
*/
protected abstract void doNonUILogic() throws RuntimeException;
/**
* This method will be implemented by the inner class of SwingWorker It
* should only consist of the logic that's related to UI updating, after the
* doNonUILogic() method is done.
*
* @throws java.lang.RuntimeException
* thrown if there are any problems executing the ui update
* logic
*/
protected abstract void doUIUpdateLogic() throws RuntimeException;
/**
* Called on the event dispatching thread (not on the worker thread) after
* the <code>construct</code> method has returned.
*/
protected void finished() {
try {
deactivateGlassPane();
doUIUpdateLogic();
} catch (RuntimeException e) {
// Do nothing, simply cleanup below
log.log(Level.WARNING, "SwingWorker error", e);
} finally {
// Allow original component to get the focus
if (getAComponent() != null) {
getAComponent().requestFocus();
}
}
}
/**
* Getter method
*
* @return java.awt.Component
*/
protected Component getAComponent() {
return aComponent;
}
/**
* Getter method
*
* @return GlassPane
*/
protected GlassPane getGlassPane() {
return glassPane;
}
/**
* A new method that interrupts the worker thread. Call this method
* to force the worker to stop what it's doing.
*/
public void interrupt() {
Thread t = threadVar.get();
if (t != null) {
t.interrupt();
}
threadVar.clear();
}
/**
* Setter method
*
* @param newAComponent java.awt.Component
*/
protected void setAComponent(Component newAComponent) {
aComponent = newAComponent;
}
/**
* Setter method
*
* @param newGlassPane GlassPane
*/
protected void setGlassPane(GlassPane newGlassPane) {
glassPane = newGlassPane;
}
/**
* Start the worker thread.
*/
public void start() {
Thread t = threadVar.get();
if (t != null) {
t.start();
}
}
}