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