GNU Classpath (0.91) | |
Frames | No Frames |
1: /* ProgressMonitor.java -- 2: Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: package javax.swing; 39: 40: import java.awt.Component; 41: import java.awt.event.ActionListener; 42: import java.awt.event.ActionEvent; 43: 44: /** 45: * <p>Using this class you can easily monitor tasks where you cannot 46: * estimate the duration exactly.</p> 47: * 48: * <p>A ProgressMonitor instance waits until the first time setProgress 49: * is called. When <code>millisToDecideToPopup</code> time elapsed the 50: * instance estimates the duration until the whole operation is completed. 51: * If this duration exceeds <code>millisToPopup</code> a non-modal dialog 52: * with a message and a progress bar is shown.</p> 53: * 54: * <p>The value of <code>millisToDecideToPopup</code> defaults to 55: * <code>500</code> and <code>millisToPopup</code> to 56: * <code>2000</code>.</p> 57: * 58: * @author Andrew Selkirk 59: * @author Robert Schuster (robertschuster@fsfe.org) 60: * @since 1.2 61: * @status updated to 1.2 62: */ 63: public class ProgressMonitor 64: { 65: /** 66: * parentComponent 67: */ 68: Component component; 69: 70: /** 71: * note 72: */ 73: String note; 74: 75: /** 76: * message 77: */ 78: Object message; 79: 80: /** 81: * millisToDecideToPopup 82: */ 83: int millisToDecideToPopup = 500; 84: 85: /** 86: * millisToPopup 87: */ 88: int millisToPopup = 2000; 89: 90: int min, max, progress; 91: 92: JProgressBar progressBar; 93: 94: JLabel noteLabel; 95: 96: JDialog progressDialog; 97: 98: Timer timer; 99: 100: boolean canceled; 101: 102: /** 103: * Creates a new <code>ProgressMonitor</code> instance. This is used to 104: * monitor a task and pops up a dialog if the task is taking a long time to 105: * run. 106: * 107: * @param component The parent component of the progress dialog or 108: * <code>null</code>. 109: * @param message A constant message object which works in the way it does 110: * in {@link JOptionPane}. 111: * @param note A string message which can be changed while the operation goes 112: * on. 113: * @param minimum The minimum value for the operation (start value). 114: * @param maximum The maximum value for the operation (end value). 115: */ 116: public ProgressMonitor(Component component, Object message, 117: String note, int minimum, int maximum) 118: { 119: 120: // Set data. 121: this.component = component; 122: this.message = message; 123: this.note = note; 124: 125: min = minimum; 126: max = maximum; 127: } 128: 129: /** 130: * <p>Hides the dialog and stops any measurements.</p> 131: * 132: * <p>Has no effect when <code>setProgress</code> is not at least 133: * called once.</p> 134: */ 135: public void close() 136: { 137: if ( progressDialog != null ) 138: { 139: progressDialog.setVisible(false); 140: } 141: 142: if ( timer != null ) 143: { 144: timer.stop(); 145: timer = null; 146: } 147: } 148: 149: /** 150: * <p>Updates the progress value.</p> 151: * 152: * <p>When called for the first time this initializes a timer 153: * which decides after <code>millisToDecideToPopup</code> time 154: * whether to show a progress dialog or not.</p> 155: * 156: * <p>If the progress value equals or exceeds the maximum 157: * value the progress dialog is closed automatically.</p> 158: * 159: * @param progress New progress value. 160: */ 161: public void setProgress(int progress) 162: { 163: this.progress = progress; 164: 165: // Initializes and starts a timer with a task 166: // which measures the duration and displays 167: // a progress dialog if neccessary. 168: if ( timer == null && progressDialog == null ) 169: { 170: timer = new Timer(25, null); 171: timer.addActionListener(new TimerListener()); 172: timer.start(); 173: } 174: 175: // Cancels timer and hides progress dialog if the 176: // maximum value is reached. 177: if ( progressBar != null && this.progress >= progressBar.getMaximum() ) 178: { 179: // The reason for using progressBar.getMaximum() instead of max is that 180: // we want to prevent that changes to the value have any effect after the 181: // progress dialog is visible (This is how the JDK behaves.). 182: close(); 183: } 184: 185: } 186: 187: /** 188: * Returns the minimum or start value of the operation. 189: * 190: * @return Minimum or start value of the operation. 191: */ 192: public int getMinimum() 193: { 194: return min; 195: } 196: 197: /** 198: * <p>Use this method to set the minimum or start value of 199: * your operation.</p> 200: * 201: * <p>For typical application like copy operation this will be 202: * zero.</p> 203: * 204: * <p>Keep in mind that changing this value after the progress 205: * dialog is made visible has no effect upon the progress bar.</p> 206: * 207: * @param minimum The new minimum value. 208: */ 209: public void setMinimum(int minimum) 210: { 211: min = minimum; 212: } 213: 214: /** 215: * Return the maximum or end value of your operation. 216: * 217: * @return Maximum or end value. 218: */ 219: public int getMaximum() 220: { 221: return max; 222: } 223: 224: /** 225: * <p>Sets the maximum or end value of the operation to the 226: * given integer.</p> 227: * 228: * @param maximum 229: */ 230: public void setMaximum(int maximum) 231: { 232: max = maximum; 233: } 234: 235: /** 236: * Returns whether the user canceled the operation. 237: * 238: * @return Whether the operation was canceled. 239: */ 240: public boolean isCanceled() 241: { 242: // The value is predefined to false 243: // and changes only when the user clicks 244: // the cancel button in the progress dialog. 245: return canceled; 246: } 247: 248: /** 249: * Returns the amount of milliseconds to wait 250: * until the ProgressMonitor should decide whether 251: * a progress dialog is to be shown or not. 252: * 253: * @return The duration in milliseconds. 254: */ 255: public int getMillisToDecideToPopup() 256: { 257: return millisToDecideToPopup; 258: } 259: 260: /** 261: * Sets the amount of milliseconds to wait until the 262: * ProgressMonitor should decide whether a progress dialog 263: * is to be shown or not. 264: * 265: * <p>This method has no effect when the progress dialog 266: * is already visible.</p> 267: * 268: * @param time The duration in milliseconds. 269: */ 270: public void setMillisToDecideToPopup(int time) 271: { 272: millisToDecideToPopup = time; 273: } 274: 275: /** 276: * Returns the number of milliseconds to wait before displaying the progress 277: * dialog. The default value is 2000. 278: * 279: * @return The number of milliseconds. 280: * 281: * @see #setMillisToPopup(int) 282: */ 283: public int getMillisToPopup() 284: { 285: return millisToPopup; 286: } 287: 288: /** 289: * Sets the number of milliseconds to wait before displaying the progress 290: * dialog. 291: * 292: * @param time the number of milliseconds. 293: * 294: * @see #getMillisToPopup() 295: */ 296: public void setMillisToPopup(int time) 297: { 298: millisToPopup = time; 299: } 300: 301: /** 302: * Returns a message which is shown in the progress dialog. 303: * 304: * @return The changeable message visible in the progress dialog. 305: */ 306: public String getNote() 307: { 308: return note; 309: } 310: 311: /** 312: * <p>Set the message shown in the progess dialog.</p> 313: * 314: * <p>Changing the note while the progress dialog is visible 315: * is possible.</p> 316: * 317: * @param note A message shown in the progress dialog. 318: */ 319: public void setNote(String note) 320: { 321: if ( noteLabel != null ) 322: { 323: noteLabel.setText(note); 324: } 325: else 326: { 327: this.note = note; 328: } 329: } 330: 331: /** 332: * Internal method that creates the progress dialog. 333: */ 334: void createDialog() 335: { 336: // If there is no note we suppress the generation of the 337: // label. 338: Object[] tmp = (note == null) ? 339: new Object[] 340: { 341: message, 342: progressBar = new JProgressBar(min, max) 343: } 344: : 345: new Object[] 346: { 347: message, 348: noteLabel = new JLabel(note), 349: progressBar = new JProgressBar(min, max) 350: }; 351: 352: JOptionPane pane = new JOptionPane(tmp, JOptionPane.INFORMATION_MESSAGE); 353: 354: // FIXME: Internationalize the button 355: JButton cancelButton = new JButton("Cancel"); 356: cancelButton.addActionListener(new ActionListener() 357: { 358: public void actionPerformed(ActionEvent ae) 359: { 360: canceled = true; 361: } 362: }); 363: 364: pane.setOptions(new Object[] { cancelButton }); 365: 366: // FIXME: Internationalize the title 367: progressDialog = pane.createDialog(component, "Progress ..."); 368: progressDialog.setModal(false); 369: progressDialog.setResizable(true); 370: 371: progressDialog.pack(); 372: progressDialog.setVisible(true); 373: 374: } 375: 376: /** An ActionListener implementation which does the measurements 377: * and estimations of the ProgressMonitor. 378: */ 379: class TimerListener implements ActionListener 380: { 381: long timestamp; 382: 383: int lastProgress; 384: 385: boolean first = true; 386: 387: TimerListener() 388: { 389: timestamp = System.currentTimeMillis(); 390: } 391: 392: public void actionPerformed(ActionEvent ae) 393: { 394: long now = System.currentTimeMillis(); 395: 396: if ( first ) 397: { 398: if (( now - timestamp ) > millisToDecideToPopup ) 399: { 400: first = false; 401: 402: 403: long expected = ( progress - min == 0 ) ? 404: ( now - timestamp ) * ( max - min ) : 405: ( now - timestamp ) * ( max - min ) / ( progress - min ); 406: 407: if ( expected > millisToPopup ) 408: { 409: createDialog(); 410: } 411: } 412: else 413: { 414: // We have not waited long enough to make a decision, 415: // so return and try again when the timer is invoked. 416: return; 417: } 418: } 419: else if ( progressDialog != null ) 420: { 421: // The progress dialog is being displayed. We now calculate 422: // whether setting the progress bar to the current progress 423: // value would result in a visual difference. 424: int delta = progress - progressBar.getValue(); 425: 426: if ( ( delta * progressBar.getWidth() / (max - min) ) > 0 ) 427: { 428: // At least one pixel would change. 429: progressBar.setValue(progress); 430: } 431: } 432: else 433: { 434: // No dialog necessary 435: timer.stop(); 436: timer = null; 437: } 438: 439: timestamp = now; 440: } 441: } 442: 443: }
GNU Classpath (0.91) |