package me.chenyi.mm.ui; import javax.swing.*; import javax.swing.border.EmptyBorder; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; /** * A simple dialog that displays a message and an animated gif to show that * work is 'in progress'. It should be used when the length of a task is not * known, but it is necessary to show that work is being done. * */ public class IndeterminateWaitDialog extends JDialog { private static final String IMAGE = "images/gears.gif"; private JLabel messageLabel; private AnimationPanel animationPanel; private boolean cancelled; private JButton cancelButton; public IndeterminateWaitDialog(Window owner) { this(owner, "Waiting...", "", false, ""); } public IndeterminateWaitDialog(Window owner, String title, String waitText, boolean includeCancelButton, String cancelText) { super(owner, title, ModalityType.MODELESS); setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); getContentPane().setLayout(new BorderLayout()); getContentPane().add(createDisplayPanel(includeCancelButton), BorderLayout.CENTER); setWaitText(waitText); setCancelText(cancelText); } public boolean isCancelled() { return cancelled; } public void showDialog(Runnable r) { cancelled = false; Thread thread = new Thread(new RunnableWrapper(this, r)); thread.start(); setModal(true); setVisible(true); } public void setWaitText(String t) { messageLabel.setText(t); } public void setCancelText(String t) { if (cancelButton != null) cancelButton.setText(t); } /** * Overriden to ensure the animation is either started or stopped. * * @param v true to show the dialog, false to hide it. */ public void setVisible(boolean v) { if (v) { pack(); setLocationRelativeTo(getParent()); // set the size and position of the dialog animationPanel.start(); } else animationPanel.stop(); super.setVisible(v); } private JPanel createDisplayPanel(boolean includeCancelButton) { JPanel p = new JPanel(false); p.setBorder(new EmptyBorder(3, 3, 3, 3)); p.setLayout(new BorderLayout(10, 10)); messageLabel = new JLabel(""); p.add(messageLabel, BorderLayout.CENTER); animationPanel = new AnimationPanel(IMAGE); p.add(animationPanel, BorderLayout.EAST); if (includeCancelButton) { cancelButton = new JButton(""); cancelButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { cancelled = true; } }); JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); p.add(buttonPanel, BorderLayout.SOUTH); buttonPanel.add(cancelButton); } return p; } /** * */ private class RunnableWrapper implements Runnable { private Runnable runnable; private JDialog dialog; public RunnableWrapper(JDialog d, Runnable r) { dialog = d; runnable = r; } public void run() { // not very nice, but nicer than before while (!dialog.isVisible()) { try { Thread.sleep(100); } catch (InterruptedException ie) { } } try { runnable.run(); } catch(Throwable t) { t.printStackTrace(); JOptionPane.showMessageDialog(dialog, "Error during processing: " + t.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); } finally { EventQueue.invokeLater(new Runnable() { public void run() { dialog.setVisible(false); dialog.dispose(); } }); } } } }