/* PleaseWaitDialog.java created 2007-10-06 * */ package org.signalml.app.view.common.dialogs; import static org.signalml.app.util.i18n.SvarogI18n._; import java.awt.Color; import java.awt.Component; import java.awt.Cursor; import java.awt.Dimension; import java.awt.Font; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import javax.swing.BoxLayout; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JProgressBar; import javax.swing.SwingWorker; import javax.swing.Timer; import javax.swing.border.CompoundBorder; import javax.swing.border.EmptyBorder; import javax.swing.border.LineBorder; import org.signalml.app.util.IconUtils; import org.signalml.plugin.export.SignalMLException; /** * Dialog shown when the user has to wait. * Contains 3 elements: * <ul> <li>the label that informs the user he should wait,</li> * <li>the progress bar, which may display actual progress or just * the animation,</li> * <li>the label that describes the action in progress.</li> * </ul> * This dialog can be shown after the specified time without it (so that maybe * the operation finishes before it is needed). * * @author Michal Dobaczewski © 2007-2008 CC Otwarte Systemy Komputerowe Sp. z o.o. */ public class PleaseWaitDialog extends AbstractDialog { private static final long serialVersionUID = 1L; /** * the label that describes the action in progress */ private JLabel activityLabel; /** * the progress bar. * May display actual progress or just the animation. */ private JProgressBar progressBar; /** * the timer that shows the dialog */ private Timer showTimer; /** * the listener for the {@link #showTimer} that shows this dialog. */ private ActionListener showListener; /** * the object that owns this dialog - usually a {@link SwingWorker} */ private Object currentOwner; /** * Constructor. Sets parent window. * This dialog blocks top-level windows. * @param w the parent window or null if there is no parent */ public PleaseWaitDialog(Window w) { super(w, true); } /** * Does nothing. */ @Override public void fillDialogFromModel(Object model) throws SignalMLException { // do nothing } /** * Does nothing. */ @Override public void fillModelFromDialog(Object model) throws SignalMLException { // do nothing } /** * Creates the interface of this dialog. * Dialog has a {@link BoxLayout} and contains (from top to bottom): * <ul> * <li>the label that informs the user he should wait,</li> * <li>the progress bar, which may display actual progress or just * the animation,</li> * <li>the label that describes the action in progress.</li> * </ul> */ @Override public JComponent createInterface() { JPanel p = new JPanel(); p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS)); CompoundBorder border = new CompoundBorder( new LineBorder(Color.LIGHT_GRAY), new EmptyBorder(10,10,10,10) ); p.setBorder(border); JLabel label = new JLabel(_("Please wait...")); label.setIcon(IconUtils.getInfoIcon()); label.setAlignmentX(Component.CENTER_ALIGNMENT); progressBar = new JProgressBar(); progressBar.setAlignmentX(Component.CENTER_ALIGNMENT); Dimension progressSize = new Dimension(220,20); progressBar.setPreferredSize(progressSize); progressBar.setMinimumSize(progressSize); progressBar.setMaximumSize(progressSize); activityLabel = new JLabel("activity"); activityLabel.setMinimumSize(new Dimension(250,1)); activityLabel.setFont(activityLabel.getFont().deriveFont(Font.PLAIN, 10F)); activityLabel.setAlignmentX(Component.CENTER_ALIGNMENT); p.add(label); p.add(progressBar); p.add(activityLabel); p.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); return p; } /** * Returns that there is no control panel. */ @Override public boolean isControlPanelEquipped() { return false; } /** * The dialog can not be canceled. */ @Override public boolean isCancellable() { return false; } /** * There is no model, so the {@code clazz} must be {@code null}. */ @Override public boolean supportsModelClass(Class<?> clazz) { return (clazz == null); } /** * Initializes this dialog. * Adds a WindowListener to this dialog. * If the owner of this dialog is a {@link SwingWorker}, * when the worker is done makes this dialog invisible. */ @Override protected void initialize() { setUndecorated(true); super.initialize(); addWindowListener(new WindowAdapter() { @Override public void windowOpened(WindowEvent e) { if (currentOwner != null) { if (currentOwner instanceof SwingWorker) { if (((SwingWorker<?,?>) currentOwner).isDone()) { setVisible(false); } } } } }); } /** * Sets that the progress bar should display only the animation instead * of a real progress. */ public void configureForIndeterminate() { progressBar.setValue(0); progressBar.setIndeterminate(true); progressBar.setStringPainted(false); } /** * Sets that the progress bar should display only the animation instead * of a real progress. */ public void configureForIndeterminateSimulated() { progressBar.setValue(0); progressBar.setIndeterminate(true); progressBar.setStringPainted(false); } /** * Sets that the progress bar should a real progress from a given range. * Sets the value of this progress to the given value * @param min the left endpoint of the interval * @param max the right endpoint of the interval * @param value the current value of the progress */ public void configureForDeterminate(int min, int max, int value) { progressBar.setMinimum(min); progressBar.setMaximum(max); progressBar.setValue(value); progressBar.setIndeterminate(false); progressBar.setStringPainted(true); } /** * Sets the left endpoint of the progress interval. * @param min the left endpoint of the interval */ public void setMinimum(int min) { progressBar.setMinimum(min); } /** * Sets the right endpoint of the progress interval * @param max the right endpoint of the interval */ public void setMaximum(int max) { progressBar.setMaximum(max); } /** * Sets the current value of the progress. * @param value the current value of the progress */ public void setProgress(int value) { progressBar.setValue(value); } /** * Sets the text that describes the action in progress. * @param activity the text that describes the action in progress */ public void setActivity(String activity) { activityLabel.setText(activity); } /** * This method waits for specified amount of time while allowing the * application to continue * THEN locks the application on a modal dialog * @param parent the window parent to this dialog * @param noDialogTimeout the amount of milliseconds without the dialog; * after that time passes this dialog is shown */ public void showDialogIn(final Component parent, int noDialogTimeout) { currentOwner = null; if (showListener == null) { showListener = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { centerInComponent(parent, 0.5, 0.5); showDialog(null, false); } }; } if (showTimer == null) { showTimer = new Timer(0, showListener); showTimer.setRepeats(false); } showTimer.setInitialDelay(noDialogTimeout); showTimer.start(); } /** * Waits a given amount of time without the dialog and when that time * passes this dialog is shown. * The application is locked on a modal dialog that cannot be closed. * During the time without the dialog the application is WAITING in * event dispatching thread. * @param parent the window parent to this dialog * @param noDialogTimeout the amount of milliseconds without the dialog; * after that time passes this dialog is shown * @param worker the worker in which the computation is performed */ @SuppressWarnings("unchecked") public void waitAndShowDialogIn(Component parent, int noDialogTimeout, SwingWorker worker) { logger.debug("Start waitAndShowDialogIn for [" + worker + "] timeout [" + noDialogTimeout + "]"); // FIXME [MD] probably should be cleared if dialog not shown after all currentOwner = worker; if (noDialogTimeout > 0) { boolean repeat; do { repeat = false; try { logger.debug("Entering wait"); worker.get(noDialogTimeout, TimeUnit.MILLISECONDS); logger.debug("Exiting wait"); } catch (InterruptedException ex) { repeat = true; } catch (ExecutionException ex) { // this is done only in order to wait for the completion, so disregard exception // (it was serviced in the worker's done method) return; } catch (TimeoutException ex) { // exit and proceed to show dialog } } while (repeat); } if (!worker.isDone()) { logger.debug("Showing dialog"); centerInComponent(parent, 0.5, 0.5); showDialog(null, false); } logger.debug("End waitAndShowDialogIn for [" + worker + "]"); } /** * Shows this dialog and locks the application on it. * @param parent the window parent to this dialog */ public void showDialogNow(Component parent) { currentOwner = null; centerInComponent(parent, 0.5, 0.5); showDialog(null, false); } /** * Cancels showDialogIn, but not other ways of timed showing. */ public void cancelShowing() { if (showTimer != null && showTimer.isRunning()) { showTimer.stop(); } currentOwner = null; } /** * Makes this dialog invisible. */ public void release() { setVisible(false); currentOwner = null; } /** * Makes the dialog invisible if the given object owns it. * @param owner if the object own this dialog, this dialog is made * invisible */ public void releaseIfOwnedBy(Object owner) { logger.debug("releaseIfOwnedBy for [" + owner + "]"); if (currentOwner == owner) { logger.debug("releasing for [" + owner + "]"); setVisible(false); currentOwner = null; } } }