| /* ProgressMonitor.java -- |
| Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc. |
| |
| This file is part of GNU Classpath. |
| |
| GNU Classpath is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GNU Classpath is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Classpath; see the file COPYING. If not, write to the |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| 02110-1301 USA. |
| |
| Linking this library statically or dynamically with other modules is |
| making a combined work based on this library. Thus, the terms and |
| conditions of the GNU General Public License cover the whole |
| combination. |
| |
| As a special exception, the copyright holders of this library give you |
| permission to link this library with independent modules to produce an |
| executable, regardless of the license terms of these independent |
| modules, and to copy and distribute the resulting executable under |
| terms of your choice, provided that you also meet, for each linked |
| independent module, the terms and conditions of the license of that |
| module. An independent module is a module which is not derived from |
| or based on this library. If you modify this library, you may extend |
| this exception to your version of the library, but you are not |
| obligated to do so. If you do not wish to do so, delete this |
| exception statement from your version. */ |
| |
| package javax.swing; |
| |
| import java.awt.Component; |
| import java.awt.event.ActionEvent; |
| import java.awt.event.ActionListener; |
| |
| import javax.accessibility.AccessibleContext; |
| |
| /** |
| * <p>Using this class you can easily monitor tasks where you cannot |
| * estimate the duration exactly.</p> |
| * |
| * <p>A ProgressMonitor instance waits until the first time setProgress |
| * is called. When <code>millisToDecideToPopup</code> time elapsed the |
| * instance estimates the duration until the whole operation is completed. |
| * If this duration exceeds <code>millisToPopup</code> a non-modal dialog |
| * with a message and a progress bar is shown.</p> |
| * |
| * <p>The value of <code>millisToDecideToPopup</code> defaults to |
| * <code>500</code> and <code>millisToPopup</code> to |
| * <code>2000</code>.</p> |
| * |
| * @author Andrew Selkirk |
| * @author Robert Schuster (robertschuster@fsfe.org) |
| * @since 1.2 |
| * @status updated to 1.2 |
| */ |
| public class ProgressMonitor |
| { |
| |
| /** |
| * The accessible content for this component |
| */ |
| protected AccessibleContext accessibleContext; |
| |
| /** |
| * parentComponent |
| */ |
| Component component; |
| |
| /** |
| * note |
| */ |
| String note; |
| |
| /** |
| * message |
| */ |
| Object message; |
| |
| /** |
| * millisToDecideToPopup |
| */ |
| int millisToDecideToPopup = 500; |
| |
| /** |
| * millisToPopup |
| */ |
| int millisToPopup = 2000; |
| |
| int min, max, progress; |
| |
| JProgressBar progressBar; |
| |
| JLabel noteLabel; |
| |
| JDialog progressDialog; |
| |
| Timer timer; |
| |
| boolean canceled; |
| |
| /** |
| * Creates a new <code>ProgressMonitor</code> instance. This is used to |
| * monitor a task and pops up a dialog if the task is taking a long time to |
| * run. |
| * |
| * @param component The parent component of the progress dialog or |
| * <code>null</code>. |
| * @param message A constant message object which works in the way it does |
| * in {@link JOptionPane}. |
| * @param note A string message which can be changed while the operation goes |
| * on. |
| * @param minimum The minimum value for the operation (start value). |
| * @param maximum The maximum value for the operation (end value). |
| */ |
| public ProgressMonitor(Component component, Object message, |
| String note, int minimum, int maximum) |
| { |
| |
| // Set data. |
| this.component = component; |
| this.message = message; |
| this.note = note; |
| |
| min = minimum; |
| max = maximum; |
| } |
| |
| /** |
| * <p>Hides the dialog and stops any measurements.</p> |
| * |
| * <p>Has no effect when <code>setProgress</code> is not at least |
| * called once.</p> |
| */ |
| public void close() |
| { |
| if (progressDialog != null) |
| { |
| progressDialog.setVisible(false); |
| } |
| |
| if (timer != null) |
| { |
| timer.stop(); |
| timer = null; |
| } |
| } |
| |
| /** |
| * <p>Updates the progress value.</p> |
| * |
| * <p>When called for the first time this initializes a timer |
| * which decides after <code>millisToDecideToPopup</code> time |
| * whether to show a progress dialog or not.</p> |
| * |
| * <p>If the progress value equals or exceeds the maximum |
| * value the progress dialog is closed automatically.</p> |
| * |
| * @param progress New progress value. |
| */ |
| public void setProgress(int progress) |
| { |
| this.progress = progress; |
| |
| // Initializes and starts a timer with a task |
| // which measures the duration and displays |
| // a progress dialog if neccessary. |
| if (timer == null && progressDialog == null) |
| { |
| timer = new Timer(25, null); |
| timer.addActionListener(new TimerListener()); |
| timer.start(); |
| } |
| |
| // Cancels timer and hides progress dialog if the |
| // maximum value is reached. |
| if (progressBar != null && this.progress >= progressBar.getMaximum()) |
| { |
| // The reason for using progressBar.getMaximum() instead of max is that |
| // we want to prevent that changes to the value have any effect after the |
| // progress dialog is visible (This is how the JDK behaves.). |
| close(); |
| } |
| |
| } |
| |
| /** |
| * Returns the minimum or start value of the operation. |
| * |
| * @return Minimum or start value of the operation. |
| */ |
| public int getMinimum() |
| { |
| return min; |
| } |
| |
| /** |
| * <p>Use this method to set the minimum or start value of |
| * your operation.</p> |
| * |
| * <p>For typical application like copy operation this will be |
| * zero.</p> |
| * |
| * <p>Keep in mind that changing this value after the progress |
| * dialog is made visible has no effect upon the progress bar.</p> |
| * |
| * @param minimum The new minimum value. |
| */ |
| public void setMinimum(int minimum) |
| { |
| min = minimum; |
| } |
| |
| /** |
| * Return the maximum or end value of your operation. |
| * |
| * @return Maximum or end value. |
| */ |
| public int getMaximum() |
| { |
| return max; |
| } |
| |
| /** |
| * <p>Sets the maximum or end value of the operation to the |
| * given integer.</p> |
| * |
| * @param maximum |
| */ |
| public void setMaximum(int maximum) |
| { |
| max = maximum; |
| } |
| |
| /** |
| * Returns whether the user canceled the operation. |
| * |
| * @return Whether the operation was canceled. |
| */ |
| public boolean isCanceled() |
| { |
| // The value is predefined to false |
| // and changes only when the user clicks |
| // the cancel button in the progress dialog. |
| return canceled; |
| } |
| |
| /** |
| * Returns the amount of milliseconds to wait |
| * until the ProgressMonitor should decide whether |
| * a progress dialog is to be shown or not. |
| * |
| * @return The duration in milliseconds. |
| */ |
| public int getMillisToDecideToPopup() |
| { |
| return millisToDecideToPopup; |
| } |
| |
| /** |
| * Sets the amount of milliseconds to wait until the |
| * ProgressMonitor should decide whether a progress dialog |
| * is to be shown or not. |
| * |
| * <p>This method has no effect when the progress dialog |
| * is already visible.</p> |
| * |
| * @param time The duration in milliseconds. |
| */ |
| public void setMillisToDecideToPopup(int time) |
| { |
| millisToDecideToPopup = time; |
| } |
| |
| /** |
| * Returns the number of milliseconds to wait before displaying the progress |
| * dialog. The default value is 2000. |
| * |
| * @return The number of milliseconds. |
| * |
| * @see #setMillisToPopup(int) |
| */ |
| public int getMillisToPopup() |
| { |
| return millisToPopup; |
| } |
| |
| /** |
| * Sets the number of milliseconds to wait before displaying the progress |
| * dialog. |
| * |
| * @param time the number of milliseconds. |
| * |
| * @see #getMillisToPopup() |
| */ |
| public void setMillisToPopup(int time) |
| { |
| millisToPopup = time; |
| } |
| |
| /** |
| * Returns a message which is shown in the progress dialog. |
| * |
| * @return The changeable message visible in the progress dialog. |
| */ |
| public String getNote() |
| { |
| return note; |
| } |
| |
| /** |
| * <p>Set the message shown in the progess dialog.</p> |
| * |
| * <p>Changing the note while the progress dialog is visible |
| * is possible.</p> |
| * |
| * @param note A message shown in the progress dialog. |
| */ |
| public void setNote(String note) |
| { |
| if (noteLabel != null) |
| { |
| noteLabel.setText(note); |
| } |
| else |
| { |
| this.note = note; |
| } |
| } |
| |
| /** |
| * Internal method that creates the progress dialog. |
| */ |
| void createDialog() |
| { |
| // If there is no note we suppress the generation of the |
| // label. |
| Object[] tmp = (note == null) ? |
| new Object[] |
| { |
| message, |
| progressBar = new JProgressBar(min, max) |
| } |
| : |
| new Object[] |
| { |
| message, |
| noteLabel = new JLabel(note), |
| progressBar = new JProgressBar(min, max) |
| }; |
| |
| JOptionPane pane = new JOptionPane(tmp, JOptionPane.INFORMATION_MESSAGE); |
| |
| // FIXME: Internationalize the button |
| JButton cancelButton = new JButton("Cancel"); |
| cancelButton.addActionListener(new ActionListener() |
| { |
| public void actionPerformed(ActionEvent ae) |
| { |
| canceled = true; |
| } |
| }); |
| |
| pane.setOptions(new Object[] { cancelButton }); |
| |
| // FIXME: Internationalize the title |
| progressDialog = pane.createDialog(component, "Progress ..."); |
| progressDialog.setModal(false); |
| progressDialog.setResizable(true); |
| |
| progressDialog.pack(); |
| progressDialog.setVisible(true); |
| |
| } |
| |
| /** An ActionListener implementation which does the measurements |
| * and estimations of the ProgressMonitor. |
| */ |
| class TimerListener implements ActionListener |
| { |
| long timestamp; |
| |
| int lastProgress; |
| |
| boolean first = true; |
| |
| TimerListener() |
| { |
| timestamp = System.currentTimeMillis(); |
| } |
| |
| public void actionPerformed(ActionEvent ae) |
| { |
| long now = System.currentTimeMillis(); |
| |
| if (first) |
| { |
| if ((now - timestamp) > millisToDecideToPopup) |
| { |
| first = false; |
| |
| |
| long expected = (progress - min == 0) ? |
| (now - timestamp) * (max - min) : |
| (now - timestamp) * (max - min) / (progress - min); |
| |
| if (expected > millisToPopup) |
| { |
| createDialog(); |
| } |
| } |
| else |
| { |
| // We have not waited long enough to make a decision, |
| // so return and try again when the timer is invoked. |
| return; |
| } |
| } |
| else if (progressDialog != null) |
| { |
| // The progress dialog is being displayed. We now calculate |
| // whether setting the progress bar to the current progress |
| // value would result in a visual difference. |
| int delta = progress - progressBar.getValue(); |
| |
| if ((delta * progressBar.getWidth() / (max - min)) > 0) |
| { |
| // At least one pixel would change. |
| progressBar.setValue(progress); |
| } |
| } |
| else |
| { |
| // No dialog necessary |
| timer.stop(); |
| timer = null; |
| } |
| |
| timestamp = now; |
| } |
| } |
| |
| /** |
| * Gets the accessible context. |
| * |
| * @return the accessible context. |
| */ |
| public AccessibleContext getAccessibleContext() |
| { |
| return accessibleContext; |
| } |
| } |