1. /*
  2. * @(#)ProgressMonitor.java 1.19 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing;
  8. import java.io.*;
  9. import java.awt.BorderLayout;
  10. import java.awt.Frame;
  11. import java.awt.Component;
  12. import java.awt.Container;
  13. import java.beans.PropertyChangeEvent;
  14. import java.beans.PropertyChangeListener;
  15. import java.awt.event.WindowAdapter;
  16. import java.awt.event.WindowEvent;
  17. /** A class to monitor the progress of some operation. If it looks
  18. * like it will take a while, a progress dialog will be popped up.
  19. * When the ProgressMonitor is created it is given a numeric range and a
  20. * descriptive string. As the operation progresses, call the setProgress method
  21. * to indicate how far along the [min,max] range the operation is.
  22. * Initially, there is no ProgressDialog. After the first millisToDecideToPopup
  23. * milliseconds (default 500) the progress monitor will predict how long
  24. * the operation will take. If it is longer than millisToPopup (default 2000,
  25. * 2 seconds) a ProgressDialog will be popped up.
  26. * <p>
  27. * From time to time, when the Dialog box is visible, the progress bar will
  28. * be updated when setProgress is called. setProgress won't always update
  29. * the progress bar, it will only be done if the amount of progress is
  30. * visibly significant.
  31. * <p>
  32. * @see ProgressMonitorInputStream
  33. * @author James Gosling
  34. * @version 1.19 11/29/01
  35. */
  36. public class ProgressMonitor extends Object
  37. {
  38. private ProgressMonitor root;
  39. private JDialog dialog;
  40. private JOptionPane pane;
  41. private JProgressBar myBar;
  42. private JLabel noteLabel;
  43. private Component parentComponent;
  44. private String note;
  45. private Object[] cancelOption = null;
  46. private Object message;
  47. private long T0;
  48. private int millisToDecideToPopup = 500;
  49. private int millisToPopup = 2000;
  50. private int min;
  51. private int max;
  52. private int v;
  53. private int lastDisp;
  54. private int reportDelta;
  55. /**
  56. * Constructs a graphic object that shows progress, typically by filling
  57. * in a rectangular bar as the process nears completion.
  58. *
  59. * @param parentComponent the parent component for the dialog box
  60. * @param message a descriptive message that will be shown
  61. * to the user to indicate what operation is being monitored.
  62. * This does not change as the operation progresses.
  63. * See the message parameters to methods in
  64. * {@link JOptionsPane#message}
  65. * for the range of values.
  66. * @param note a short note describing the state of the
  67. * operation. As the operation progresses, you can call
  68. * setNote to change the note displayed. This is used,
  69. * for example, in operations that iterate through a
  70. * list of files to show the name of the file being processes.
  71. * If note is initially null, there will be no note line
  72. * in the dialog box and setNote will be ineffective
  73. * @param min the lower bound of the range
  74. * @param max the upper bound of the range
  75. * @see JDialog
  76. * @see JOptionPane
  77. */
  78. public ProgressMonitor(Component parentComponent,
  79. Object message,
  80. String note,
  81. int min,
  82. int max) {
  83. this(parentComponent, message, note, min, max, null);
  84. }
  85. private ProgressMonitor(Component parentComponent,
  86. Object message,
  87. String note,
  88. int min,
  89. int max,
  90. ProgressMonitor group) {
  91. this.min = min;
  92. this.max = max;
  93. this.parentComponent = parentComponent;
  94. cancelOption = new Object[1];
  95. cancelOption[0] = UIManager.getString("OptionPane.cancelButtonText");
  96. reportDelta = (max - min) / 100;
  97. if (reportDelta < 1) reportDelta = 1;
  98. v = min;
  99. this.message = message;
  100. this.note = note;
  101. if (group != null) {
  102. root = (group.root != null) ? group.root : group;
  103. T0 = root.T0;
  104. dialog = root.dialog;
  105. }
  106. else {
  107. T0 = System.currentTimeMillis();
  108. }
  109. }
  110. private class ProgressOptionPane extends JOptionPane
  111. {
  112. ProgressOptionPane(Object messageList) {
  113. super(messageList,
  114. JOptionPane.INFORMATION_MESSAGE,
  115. JOptionPane.DEFAULT_OPTION,
  116. null,
  117. ProgressMonitor.this.cancelOption,
  118. null);
  119. }
  120. public int getMaxCharactersPerLineCount() {
  121. return 60;
  122. }
  123. // Equivalent to JOptionPane.createDialog,
  124. // but create a modeless dialog.
  125. // This is necessary because the Solaris implementation doesn't
  126. // support Dialog.setModal yet.
  127. public JDialog createDialog(Component parentComponent, String title) {
  128. Frame frame = JOptionPane.getFrameForComponent(parentComponent);
  129. final JDialog dialog = new JDialog(frame, title, false);
  130. Container contentPane = dialog.getContentPane();
  131. contentPane.setLayout(new BorderLayout());
  132. contentPane.add(this, BorderLayout.CENTER);
  133. dialog.pack();
  134. dialog.setLocationRelativeTo(parentComponent);
  135. dialog.addWindowListener(new WindowAdapter() {
  136. boolean gotFocus = false;
  137. public void windowClosing(WindowEvent we) {
  138. setValue(null);
  139. }
  140. public void windowActivated(WindowEvent we) {
  141. // Once window gets focus, set initial focus
  142. if (!gotFocus) {
  143. selectInitialValue();
  144. gotFocus = true;
  145. }
  146. }
  147. });
  148. addPropertyChangeListener(new PropertyChangeListener() {
  149. public void propertyChange(PropertyChangeEvent event) {
  150. if(dialog.isVisible() &&
  151. event.getSource() == ProgressOptionPane.this &&
  152. (event.getPropertyName().equals(VALUE_PROPERTY) ||
  153. event.getPropertyName().equals(INPUT_VALUE_PROPERTY))){
  154. dialog.setVisible(false);
  155. dialog.dispose();
  156. }
  157. }
  158. });
  159. return dialog;
  160. }
  161. }
  162. /**
  163. * Indicate the progress of the operation being monitored.
  164. * If the specified value is >= the maximum, the progress
  165. * monitor is closed.
  166. * @param nv an int specifying the current value, between the
  167. * maximum and minimum specified for this component
  168. * @see #setMinimum
  169. * @see #setMaximum
  170. * @see #close
  171. */
  172. public void setProgress(int nv) {
  173. v = nv;
  174. if (nv >= max) {
  175. close();
  176. }
  177. else if (nv >= lastDisp + reportDelta) {
  178. lastDisp = nv;
  179. if (myBar != null) {
  180. myBar.setValue(nv);
  181. }
  182. else {
  183. long T = System.currentTimeMillis();
  184. long dT = (int)(T-T0);
  185. if (dT >= millisToDecideToPopup) {
  186. int predictedCompletionTime;
  187. if (nv > min) {
  188. predictedCompletionTime = (int)((long)dT *
  189. (max - min) /
  190. (nv - min));
  191. }
  192. else {
  193. predictedCompletionTime = millisToPopup;
  194. }
  195. if (predictedCompletionTime >= millisToPopup) {
  196. myBar = new JProgressBar();
  197. myBar.setMinimum(min);
  198. myBar.setMaximum(max);
  199. myBar.setValue(nv);
  200. if (note != null) noteLabel = new JLabel(note);
  201. pane = new ProgressOptionPane(new Object[] {message,
  202. noteLabel,
  203. myBar});
  204. dialog = pane.createDialog(parentComponent,
  205. "Progress...");
  206. dialog.show();
  207. }
  208. }
  209. }
  210. }
  211. }
  212. /**
  213. * Indicate that the operation is complete. This happens automatically
  214. * when the value set by setProgress is >= max, but it may be called
  215. * earlier if the operation ends early.
  216. */
  217. public void close() {
  218. if (dialog != null) {
  219. dialog.setVisible(false);
  220. dialog.dispose();
  221. dialog = null;
  222. pane = null;
  223. myBar = null;
  224. }
  225. }
  226. /**
  227. * Returns the minimum value -- the lower end of the progress value.
  228. *
  229. * @return an int representing the minimum value
  230. * @see #setMinimum
  231. */
  232. public int getMinimum() {
  233. return min;
  234. }
  235. /**
  236. * Specifies the minimum value.
  237. *
  238. * @param m an int specifying the minimum value
  239. * @see #getMinimum
  240. */
  241. public void setMinimum(int m) {
  242. min = m;
  243. }
  244. /**
  245. * Returns the maximum value -- the higher end of the progress value.
  246. *
  247. * @return an int representing the maximum value
  248. * @see #setMaximum
  249. */
  250. public int getMaximum() {
  251. return max;
  252. }
  253. /**
  254. * Specifies the maximum value.
  255. *
  256. * @param m an int specifying the maximum value
  257. * @see #getMaximum
  258. */
  259. public void setMaximum(int m) {
  260. max = m;
  261. }
  262. /**
  263. * Returns true if the user hits the Cancel button in the progress dialog.
  264. */
  265. public boolean isCanceled() {
  266. if (pane == null) return false;
  267. Object v = pane.getValue();
  268. return ((v != null) &&
  269. (cancelOption.length == 1) &&
  270. (v.equals(cancelOption[0])));
  271. }
  272. /**
  273. * Specifies the amount of time to wait before deciding whether or
  274. * not to popup a progress monitor.
  275. *
  276. * @param millisToDecideToPopup an int specifying the time to wait,
  277. * in milliseconds
  278. * @see #getMillisToDecideToPopup
  279. */
  280. public void setMillisToDecideToPopup(int millisToDecideToPopup) {
  281. this.millisToDecideToPopup = millisToDecideToPopup;
  282. }
  283. /**
  284. * Returns the amount of time this object waits before deciding whether
  285. * or not to popup a progress monitor.
  286. *
  287. * @param millisToDecideToPopup an int specifying waiting time,
  288. * in milliseconds
  289. * @see #setMillisToDecideToPopup
  290. */
  291. public int getMillisToDecideToPopup() {
  292. return millisToDecideToPopup;
  293. }
  294. /**
  295. * Specifies the amount of time it will take for the popup to appear.
  296. * (If the predicted time remaining is less than this time, the popup
  297. * won't be displayed.)
  298. *
  299. * @param millisToPopup an int specifying the time in milliseconds
  300. * @see #getMillisToPopup
  301. */
  302. public void setMillisToPopup(int millisToPopup) {
  303. this.millisToPopup = millisToPopup;
  304. }
  305. /**
  306. * Returns the amount of time it will take for the popup to appear.
  307. *
  308. * @param millisToPopup an int specifying the time in milliseconds
  309. * @see #setMillisToPopup
  310. */
  311. public int getMillisToPopup() {
  312. return millisToPopup;
  313. }
  314. /**
  315. * Specifies the additional note that is displayed along with the
  316. * progress message. Used, for example, to show which file the
  317. * is currently being copied during a multiple-file copy.
  318. *
  319. * @param note a String specifying the note to display
  320. * @see #getNote
  321. */
  322. public void setNote(String note) {
  323. this.note = note;
  324. if (noteLabel != null) {
  325. noteLabel.setText(note);
  326. }
  327. }
  328. /**
  329. * Specifies the additional note that is displayed along with the
  330. * progress message.
  331. *
  332. * @return a String specifying the note to display
  333. * @see #setNote
  334. */
  335. public String getNote() {
  336. return note;
  337. }
  338. }