/***************************************************
*
* cismet GmbH, Saarbruecken, Germany
*
* ... and it just works.
*
****************************************************/
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package de.cismet.tools.gui;
import org.apache.log4j.Logger;
import org.openide.util.Cancellable;
import java.awt.EventQueue;
import java.util.concurrent.locks.ReentrantLock;
import javax.swing.Icon;
/**
* Executes a task in the background and shows a WaitingDialog until the end of the task.
*
* @author therter
* @version $Revision$, $Date$
*/
public abstract class WaitingDialogThread<T> implements Runnable, Cancellable {
//~ Static fields/initializers ---------------------------------------------
private static final Logger LOG = Logger.getLogger(WaitingDialogThread.class);
//~ Instance fields --------------------------------------------------------
protected WaitDialog wd;
private int delay = 0;
private volatile boolean isAlive = true;
private volatile boolean shouldBeSetVisible = false;
private final java.awt.Frame parent;
private final boolean modal;
private final String text;
private final Icon icon;
private T backgroundResult;
private Exception thrownException;
private final boolean cancellable;
private Thread worker = null;
private boolean canceled = false;
//~ Constructors -----------------------------------------------------------
/**
* Creates a new WaitingDialogThread object.
*
* @param parent paretn frame
* @param modal true, if the dialog should be modal
* @param text the text that should be shown in the dialog
* @param icon the icon of the dialog
* @param delay after this delay, the dialog should be shown
*/
public WaitingDialogThread(final java.awt.Frame parent,
final boolean modal,
final String text,
final Icon icon,
final int delay) {
this(parent, modal, text, icon, delay, false);
}
/**
* Creates a new WaitingDialogThread object.
*
* @param parent paretn frame
* @param modal true, if the dialog should be modal
* @param text the text that should be shown in the dialog
* @param icon the icon of the dialog
* @param delay after this delay, the dialog should be shown
* @param cancellable true, if a cancel button should be shown and the {@link #doInBackground()} method should
* handle the interrupt signal, if this is true
*/
public WaitingDialogThread(final java.awt.Frame parent,
final boolean modal,
final String text,
final Icon icon,
final int delay,
final boolean cancellable) {
this.parent = parent;
this.modal = modal;
this.text = text;
this.icon = icon;
this.delay = delay;
this.cancellable = cancellable;
}
//~ Methods ----------------------------------------------------------------
@Override
public final void run() {
try {
backgroundResult = doInBackground();
} catch (Exception e) {
thrownException = e;
}
}
/**
* The task that should be executed is implemented in this method.
*
* @return the result of the task. This result can be accessed in the done method
*
* @throws Exception DOCUMENT ME!
*/
protected abstract T doInBackground() throws Exception;
/**
* This method is executed in the edt after the backgrund task.
*/
protected void done() {
}
/**
* provides the result of the background task.
*
* @return the result of the background task
*
* @throws Exception the exception, that was thrown in the background task
*/
protected T get() throws Exception {
if (thrownException != null) {
throw thrownException;
} else {
return backgroundResult;
}
}
@Override
public boolean cancel() {
canceled = true;
try {
worker.interrupt();
} catch (SecurityException e) {
return false;
}
return true;
}
/**
* starts the implemented task.
*/
public void start() {
if (!EventQueue.isDispatchThread()) {
LOG.error("The start method of the WaitingDialogThread must be invoked in the Edt.");
return;
}
isAlive = true;
shouldBeSetVisible = false;
thrownException = null;
final ReentrantLock lock = new ReentrantLock();
if (cancellable) {
wd = new WaitDialog(parent, modal, text, icon, this);
} else {
wd = new WaitDialog(parent, modal, text, icon);
}
final Thread t = new Thread(new Runnable() {
@Override
public void run() {
try {
worker = new Thread(WaitingDialogThread.this);
worker.start();
try {
worker.join();
} catch (InterruptedException e) {
// nothing to do
}
} finally {
if (shouldBeSetVisible) {
try {
lock.lock();
isAlive = false;
while (!wd.isVisible()) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
// nothing to do
}
}
wd.setVisible(false);
wd.dispose();
} finally {
lock.unlock();
}
}
}
}
});
t.start();
if (delay > 0) {
try {
t.join(delay);
} catch (InterruptedException e) {
// nothing to do
}
}
try {
lock.lock();
if (t.isAlive() && isAlive) {
shouldBeSetVisible = true;
}
} finally {
lock.unlock();
}
if (shouldBeSetVisible) {
// show the waiting dialog
StaticSwingTools.showDialog(wd);
}
if (!canceled) {
// starts the task in the edt without waiting dialog
done();
}
}
}