001package arcommon.ui.window; 002 003import java.awt.Container; 004import java.awt.Dimension; 005import java.awt.GridBagConstraints; 006import java.awt.GridBagLayout; 007import java.awt.event.ActionEvent; 008import java.awt.event.ActionListener; 009import java.awt.event.WindowEvent; 010 011import javax.swing.JButton; 012import javax.swing.JLabel; 013import javax.swing.JPanel; 014import javax.swing.SwingUtilities; 015import javax.swing.border.EmptyBorder; 016 017import arcommon.MyTimer; 018import arcommon.ui.other.GUIUtil; 019 020public class SimpleProgressJDialog extends AbstractJDialog { 021 022 public static final int PREFERRED_WIDTH_NOT_SET = -1; 023 024 private static SimpleProgressJDialog progressJDialog; 025 026 public static SimpleProgressJDialog createProgressJDialog(String title) { 027 return createProgressJDialog(title, "Started"); 028 } 029 030 public static SimpleProgressJDialog createProgressJDialog(String title, String progress) { 031 return createProgressJDialog(title, progress, true); 032 } 033 034 public static SimpleProgressJDialog createProgressJDialog(String title, String progress, int preferredWidth) { 035 return createProgressJDialog(title, progress, preferredWidth, true); 036 } 037 038 public static SimpleProgressJDialog createProgressJDialog(String title, String progress, boolean cancelable) { 039 return createProgressJDialog(title, progress, PREFERRED_WIDTH_NOT_SET, cancelable); 040 } 041 042 /** 043 * Note: The dialog is setVisible(true) invoked later!! 044 */ 045 public static SimpleProgressJDialog createProgressJDialog(final String title, final String progress, final int preferredWidth, final boolean cancelable) { 046 GUIUtil.runInEventThreadAndWait(new Runnable() { 047 public void run() { 048 if (progressJDialog != null) { 049 progressJDialog.dispose(); 050 progressJDialog = null; 051 } 052 053 progressJDialog = new SimpleProgressJDialog(title, progress, preferredWidth, cancelable); 054 } 055 }); 056 057 return progressJDialog; 058 } 059 060 private boolean hasBeenCanceled; 061 062 private JLabel progressJLabel; 063 private JButton cancelJButton; 064 065 public SimpleProgressJDialog(String title) { 066 this(title, "Started"); 067 } 068 069 public SimpleProgressJDialog(String title, String progress) { 070 this(title, progress, true); 071 } 072 073 public SimpleProgressJDialog(String title, String progress, int preferredWidth) { 074 this(title, progress, preferredWidth, true); 075 } 076 077 public SimpleProgressJDialog(String title, String progress, boolean cancelable) { 078 this(title, progress, PREFERRED_WIDTH_NOT_SET, true); 079 } 080 081 public SimpleProgressJDialog(String title, String progress, int preferredWidth, boolean cancelable) { 082 super(title, cancelable); 083 084 JPanel panel = new JPanel(); 085 getContentPane().add(panel); 086 panel.setLayout(new GridBagLayout()); 087 panel.setBorder(new EmptyBorder(3, 1, 3, 3)); 088 089 GridBagConstraints gridBagConstraints = new GridBagConstraints(); 090 gridBagConstraints.fill = GridBagConstraints.BOTH; 091 gridBagConstraints.weightx = 1.0; 092 gridBagConstraints.weighty = 1.0; 093 gridBagConstraints.gridy = 0; 094 gridBagConstraints.gridx = 0; 095 096 progressJLabel = new JLabel(progress); 097 panel.add(progressJLabel, gridBagConstraints); 098 099 if (cancelable) { 100 gridBagConstraints.fill = GridBagConstraints.VERTICAL; 101 gridBagConstraints.anchor = GridBagConstraints.CENTER; 102 gridBagConstraints.gridy = 1; 103 gridBagConstraints.weightx = 0.0; 104 gridBagConstraints.weighty = 0.0; 105 106 cancelJButton = new JButton("Cancel"); 107 panel.add(cancelJButton, gridBagConstraints); 108 cancelJButton.requestFocus(); 109 cancelJButton.addActionListener(new ActionListener() { 110 public void actionPerformed(ActionEvent e) { 111 requestCancel(); 112 } 113 }); 114 } 115 116 if (preferredWidth != PREFERRED_WIDTH_NOT_SET) { 117 progressJLabel.setPreferredSize(new Dimension(preferredWidth, progressJLabel.getPreferredSize().height)); 118 } 119 120 setResizable(false); 121 122 // This is run invoked later to avoid that calling setVisible(true) on this modal dialog causes the GUI thread to be blocked here. 123 Runnable runnable1 = new Runnable() { 124 public void run() { 125 setVisible(true); 126 } 127 }; 128 SwingUtilities.invokeLater(runnable1); 129 130 // This is run invoked later as a separate runnable to make it run after setVisible(true) to make it work, but setVisible(true) is blocking until the dialog is closed, so two runnables are required. 131 // The MyTimer.addActionListener(1... code is added to make GUIUtil.packAndCenterOnScreen() work the first time the dialog is shown. If it fails the dialog is very small. It is unclear why this solves the problem. 132 MyTimer.addActionListener(1, new ActionListener() { 133 @Override 134 public void actionPerformed(ActionEvent e) { 135 final ActionListener actionListenerFinal = this; 136 Runnable runnable2 = new Runnable() { 137 public void run() { 138 Container parent = SimpleProgressJDialog.this.getParent(); 139 if (parent == null) { 140 GUIUtil.packAndCenterOnScreen(SimpleProgressJDialog.this); 141 } else { 142 SimpleProgressJDialog.this.pack(); 143 GUIUtil.centerOnParent(SimpleProgressJDialog.this); 144 } 145 Dimension size = SimpleProgressJDialog.this.getSize(); 146 boolean visible = SimpleProgressJDialog.this.isVisible(); 147 if ((size.height > 50 && size.width > 50) || !visible) { 148 MyTimer.removeActionListener(actionListenerFinal); 149 } 150 } 151 }; 152 SwingUtilities.invokeLater(runnable2); 153 } 154 }); 155 } 156 157 public void setProgress(final String progress) { 158 Runnable runnable = new Runnable() { 159 public void run() { 160 if (!isVisible()) { 161 return ; 162 } 163 164 progressJLabel.setText(progress); 165 } 166 }; 167 GUIUtil.runInEventThread(runnable); 168 } 169 170 @Override 171 protected boolean canClose() { 172 return false; 173 } 174 175 @Override 176 public void windowClosing(WindowEvent e) { 177 super.windowClosing(e); 178 requestCancel(); 179 } 180 181 public void requestCancel() { 182 Runnable runnable = new Runnable() { 183 public void run() { 184 if (cancelJButton == null) { 185 return ; 186 } 187 188 cancelJButton.setEnabled(false); 189 cancelJButton.setText("Cancel requested"); 190 hasBeenCanceled = true; 191 } 192 }; 193 GUIUtil.runInEventThread(runnable); 194 } 195 196 public boolean hasBeenCanceled() { 197 return hasBeenCanceled; 198 } 199 200 private static final long serialVersionUID = -8259154457653693257L; 201}