1 /*
   2  * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javax.swing;
  27 
  28 import java.awt.Color;
  29 import java.awt.Graphics;
  30 
  31 import java.text.Format;
  32 import java.text.NumberFormat;
  33 
  34 import java.io.Serializable;
  35 import java.io.ObjectOutputStream;
  36 import java.io.ObjectInputStream;
  37 import java.io.IOException;
  38 
  39 import javax.swing.event.*;
  40 import javax.accessibility.*;
  41 import javax.swing.plaf.ProgressBarUI;
  42 
  43 
  44 /**
  45  * A component that visually displays the progress of some task.  As the task
  46  * progresses towards completion, the progress bar displays the
  47  * task's percentage of completion.
  48  * This percentage is typically represented visually by a rectangle which
  49  * starts out empty and gradually becomes filled in as the task progresses.
  50  * In addition, the progress bar can display a textual representation of this
  51  * percentage.
  52  * <p>
  53  * {@code JProgressBar} uses a {@code BoundedRangeModel} as its data model,
  54  * with the {@code value} property representing the "current" state of the task,
  55  * and the {@code minimum} and {@code maximum} properties representing the
  56  * beginning and end points, respectively.
  57  * <p>
  58  * To indicate that a task of unknown length is executing,
  59  * you can put a progress bar into indeterminate mode.
  60  * While the bar is in indeterminate mode,
  61  * it animates constantly to show that work is occurring.
  62  * As soon as you can determine the task's length and amount of progress,
  63  * you should update the progress bar's value
  64  * and switch it back to determinate mode.
  65  *
  66  * <p>
  67  *
  68  * Here is an example of creating a progress bar,
  69  * where <code>task</code> is an object (representing some piece of work)
  70  * which returns information about the progress of the task:
  71  *
  72  *<pre>
  73  *progressBar = new JProgressBar(0, task.getLengthOfTask());
  74  *progressBar.setValue(0);
  75  *progressBar.setStringPainted(true);
  76  *</pre>
  77  *
  78  * Here is an example of querying the current state of the task, and using
  79  * the returned value to update the progress bar:
  80  *
  81  *<pre>
  82  *progressBar.setValue(task.getCurrent());
  83  *</pre>
  84  *
  85  * Here is an example of putting a progress bar into
  86  * indeterminate mode,
  87  * and then switching back to determinate mode
  88  * once the length of the task is known:
  89  *
  90  *<pre>
  91  *progressBar = new JProgressBar();
  92  *<em>...//when the task of (initially) unknown length begins:</em>
  93  *progressBar.setIndeterminate(true);
  94  *<em>...//do some work; get length of task...</em>
  95  *progressBar.setMaximum(newLength);
  96  *progressBar.setValue(newValue);
  97  *progressBar.setIndeterminate(false);
  98  *</pre>
  99  *
 100  * <p>
 101  *
 102  * For complete examples and further documentation see
 103  * <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/progress.html" target="_top">How to Monitor Progress</a>,
 104  * a section in <em>The Java Tutorial.</em>
 105  *
 106  * <p>
 107  * <strong>Warning:</strong> Swing is not thread safe. For more
 108  * information see <a
 109  * href="package-summary.html#threading">Swing's Threading
 110  * Policy</a>.
 111  * <p>
 112  * <strong>Warning:</strong>
 113  * Serialized objects of this class will not be compatible with
 114  * future Swing releases. The current serialization support is
 115  * appropriate for short term storage or RMI between applications running
 116  * the same version of Swing.  As of 1.4, support for long term storage
 117  * of all JavaBeans<sup><font size="-2">TM</font></sup>
 118  * has been added to the <code>java.beans</code> package.
 119  * Please see {@link java.beans.XMLEncoder}.
 120  *
 121  * @see javax.swing.plaf.basic.BasicProgressBarUI
 122  * @see javax.swing.BoundedRangeModel
 123  * @see javax.swing.SwingWorker
 124  *
 125  * @beaninfo
 126  *      attribute: isContainer false
 127  *    description: A component that displays an integer value.
 128  *
 129  * @author Michael C. Albers
 130  * @author Kathy Walrath
 131  */
 132 public class JProgressBar extends JComponent implements SwingConstants, Accessible
 133 {
 134     /**
 135      * @see #getUIClassID
 136      */
 137     private static final String uiClassID = "ProgressBarUI";
 138 
 139     /**
 140      * Whether the progress bar is horizontal or vertical.
 141      * The default is <code>HORIZONTAL</code>.
 142      *
 143      * @see #setOrientation
 144      */
 145     protected int orientation;
 146 
 147     /**
 148      * Whether to display a border around the progress bar.
 149      * The default is <code>true</code>.
 150      *
 151      * @see #setBorderPainted
 152      */
 153     protected boolean paintBorder;
 154 
 155     /**
 156      * The object that holds the data for the progress bar.
 157      *
 158      * @see #setModel
 159      */
 160     protected BoundedRangeModel model;
 161 
 162     /**
 163      * An optional string that can be displayed on the progress bar.
 164      * The default is <code>null</code>. Setting this to a non-<code>null</code>
 165      * value does not imply that the string will be displayed.
 166      * To display the string, {@code paintString} must be {@code true}.
 167      *
 168      * @see #setString
 169      * @see #setStringPainted
 170      */
 171     protected String progressString;
 172 
 173     /**
 174      * Whether to display a string of text on the progress bar.
 175      * The default is <code>false</code>.
 176      * Setting this to <code>true</code> causes a textual
 177      * display of the progress to be rendered on the progress bar. If
 178      * the <code>progressString</code> is <code>null</code>,
 179      * the percentage of completion is displayed on the progress bar.
 180      * Otherwise, the <code>progressString</code> is
 181      * rendered on the progress bar.
 182      *
 183      * @see #setStringPainted
 184      * @see #setString
 185      */
 186     protected boolean paintString;
 187 
 188     /**
 189      * The default minimum for a progress bar is 0.
 190      */
 191     static final private int defaultMinimum = 0;
 192     /**
 193      * The default maximum for a progress bar is 100.
 194      */
 195     static final private int defaultMaximum = 100;
 196     /**
 197      * The default orientation for a progress bar is <code>HORIZONTAL</code>.
 198      */
 199     static final private int defaultOrientation = HORIZONTAL;
 200 
 201     /**
 202      * Only one <code>ChangeEvent</code> is needed per instance since the
 203      * event's only interesting property is the immutable source, which
 204      * is the progress bar.
 205      * The event is lazily created the first time that an
 206      * event notification is fired.
 207      *
 208      * @see #fireStateChanged
 209      */
 210     protected transient ChangeEvent changeEvent = null;
 211 
 212     /**
 213      * Listens for change events sent by the progress bar's model,
 214      * redispatching them
 215      * to change-event listeners registered upon
 216      * this progress bar.
 217      *
 218      * @see #createChangeListener
 219      */
 220     protected ChangeListener changeListener = null;
 221 
 222     /**
 223      * Format used when displaying percent complete.
 224      */
 225     private transient Format format;
 226 
 227     /**
 228      * Whether the progress bar is indeterminate (<code>true</code>) or
 229      * normal (<code>false</code>); the default is <code>false</code>.
 230      *
 231      * @see #setIndeterminate
 232      * @since 1.4
 233      */
 234     private boolean indeterminate;
 235 
 236 
 237    /**
 238      * Creates a horizontal progress bar
 239      * that displays a border but no progress string.
 240      * The initial and minimum values are 0,
 241      * and the maximum is 100.
 242      *
 243      * @see #setOrientation
 244      * @see #setBorderPainted
 245      * @see #setStringPainted
 246      * @see #setString
 247      * @see #setIndeterminate
 248      */
 249     public JProgressBar()
 250     {
 251         this(defaultOrientation);
 252     }
 253 
 254    /**
 255      * Creates a progress bar with the specified orientation,
 256      * which can be
 257      * either {@code SwingConstants.VERTICAL} or
 258      * {@code SwingConstants.HORIZONTAL}.
 259      * By default, a border is painted but a progress string is not.
 260      * The initial and minimum values are 0,
 261      * and the maximum is 100.
 262      *
 263      * @param orient  the desired orientation of the progress bar
 264      * @throws IllegalArgumentException if {@code orient} is an illegal value
 265      *
 266      * @see #setOrientation
 267      * @see #setBorderPainted
 268      * @see #setStringPainted
 269      * @see #setString
 270      * @see #setIndeterminate
 271      */
 272     public JProgressBar(int orient)
 273     {
 274         this(orient, defaultMinimum, defaultMaximum);
 275     }
 276 
 277 
 278     /**
 279      * Creates a horizontal progress bar
 280      * with the specified minimum and maximum.
 281      * Sets the initial value of the progress bar to the specified minimum.
 282      * By default, a border is painted but a progress string is not.
 283      * <p>
 284      * The <code>BoundedRangeModel</code> that holds the progress bar's data
 285      * handles any issues that may arise from improperly setting the
 286      * minimum, initial, and maximum values on the progress bar.
 287      * See the {@code BoundedRangeModel} documentation for details.
 288      *
 289      * @param min  the minimum value of the progress bar
 290      * @param max  the maximum value of the progress bar
 291      *
 292      * @see BoundedRangeModel
 293      * @see #setOrientation
 294      * @see #setBorderPainted
 295      * @see #setStringPainted
 296      * @see #setString
 297      * @see #setIndeterminate
 298      */
 299     public JProgressBar(int min, int max)
 300     {
 301         this(defaultOrientation, min, max);
 302     }
 303 
 304 
 305     /**
 306      * Creates a progress bar using the specified orientation,
 307      * minimum, and maximum.
 308      * By default, a border is painted but a progress string is not.
 309      * Sets the initial value of the progress bar to the specified minimum.
 310      * <p>
 311      * The <code>BoundedRangeModel</code> that holds the progress bar's data
 312      * handles any issues that may arise from improperly setting the
 313      * minimum, initial, and maximum values on the progress bar.
 314      * See the {@code BoundedRangeModel} documentation for details.
 315      *
 316      * @param orient  the desired orientation of the progress bar
 317      * @param min  the minimum value of the progress bar
 318      * @param max  the maximum value of the progress bar
 319      * @throws IllegalArgumentException if {@code orient} is an illegal value
 320      *
 321      * @see BoundedRangeModel
 322      * @see #setOrientation
 323      * @see #setBorderPainted
 324      * @see #setStringPainted
 325      * @see #setString
 326      * @see #setIndeterminate
 327      */
 328     public JProgressBar(int orient, int min, int max)
 329     {
 330         // Creating the model this way is a bit simplistic, but
 331         //  I believe that it is the the most common usage of this
 332         //  component - it's what people will expect.
 333         setModel(new DefaultBoundedRangeModel(min, 0, min, max));
 334         updateUI();
 335 
 336         setOrientation(orient);      // documented with set/getOrientation()
 337         setBorderPainted(true);      // documented with is/setBorderPainted()
 338         setStringPainted(false);     // see setStringPainted
 339         setString(null);             // see getString
 340         setIndeterminate(false);     // see setIndeterminate
 341     }
 342 
 343 
 344     /**
 345      * Creates a horizontal progress bar
 346      * that uses the specified model
 347      * to hold the progress bar's data.
 348      * By default, a border is painted but a progress string is not.
 349      *
 350      * @param newModel  the data model for the progress bar
 351      *
 352      * @see #setOrientation
 353      * @see #setBorderPainted
 354      * @see #setStringPainted
 355      * @see #setString
 356      * @see #setIndeterminate
 357      */
 358     public JProgressBar(BoundedRangeModel newModel)
 359     {
 360         setModel(newModel);
 361         updateUI();
 362 
 363         setOrientation(defaultOrientation);  // see setOrientation()
 364         setBorderPainted(true);              // see setBorderPainted()
 365         setStringPainted(false);             // see setStringPainted
 366         setString(null);                     // see getString
 367         setIndeterminate(false);             // see setIndeterminate
 368     }
 369 
 370 
 371     /**
 372      * Returns {@code SwingConstants.VERTICAL} or
 373      * {@code SwingConstants.HORIZONTAL}, depending on the orientation
 374      * of the progress bar. The default orientation is
 375      * {@code SwingConstants.HORIZONTAL}.
 376      *
 377      * @return <code>HORIZONTAL</code> or <code>VERTICAL</code>
 378      * @see #setOrientation
 379      */
 380     public int getOrientation() {
 381         return orientation;
 382     }
 383 
 384 
 385    /**
 386      * Sets the progress bar's orientation to <code>newOrientation</code>,
 387      * which must be {@code SwingConstants.VERTICAL} or
 388      * {@code SwingConstants.HORIZONTAL}. The default orientation
 389      * is {@code SwingConstants.HORIZONTAL}.
 390      *
 391      * @param  newOrientation  <code>HORIZONTAL</code> or <code>VERTICAL</code>
 392      * @exception      IllegalArgumentException    if <code>newOrientation</code>
 393      *                                              is an illegal value
 394      * @see #getOrientation
 395      *
 396      * @beaninfo
 397      *    preferred: true
 398      *        bound: true
 399      *    attribute: visualUpdate true
 400      *  description: Set the progress bar's orientation.
 401      */
 402     public void setOrientation(int newOrientation) {
 403         if (orientation != newOrientation) {
 404             switch (newOrientation) {
 405             case VERTICAL:
 406             case HORIZONTAL:
 407                 int oldOrientation = orientation;
 408                 orientation = newOrientation;
 409                 firePropertyChange("orientation", oldOrientation, newOrientation);
 410                 if (accessibleContext != null) {
 411                     accessibleContext.firePropertyChange(
 412                             AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
 413                             ((oldOrientation == VERTICAL)
 414                              ? AccessibleState.VERTICAL
 415                              : AccessibleState.HORIZONTAL),
 416                             ((orientation == VERTICAL)
 417                              ? AccessibleState.VERTICAL
 418                              : AccessibleState.HORIZONTAL));
 419                 }
 420                 break;
 421             default:
 422                 throw new IllegalArgumentException(newOrientation +
 423                                              " is not a legal orientation");
 424             }
 425             revalidate();
 426         }
 427     }
 428 
 429 
 430     /**
 431      * Returns the value of the <code>stringPainted</code> property.
 432      *
 433      * @return the value of the <code>stringPainted</code> property
 434      * @see    #setStringPainted
 435      * @see    #setString
 436      */
 437     public boolean isStringPainted() {
 438         return paintString;
 439     }
 440 
 441 
 442     /**
 443      * Sets the value of the <code>stringPainted</code> property,
 444      * which determines whether the progress bar
 445      * should render a progress string.
 446      * The default is <code>false</code>, meaning
 447      * no string is painted.
 448      * Some look and feels might not support progress strings
 449      * or might support them only when the progress bar is in determinate mode.
 450      *
 451      * @param   b       <code>true</code> if the progress bar should render a string
 452      * @see     #isStringPainted
 453      * @see     #setString
 454      * @beaninfo
 455      *        bound: true
 456      *    attribute: visualUpdate true
 457      *  description: Whether the progress bar should render a string.
 458      */
 459     public void setStringPainted(boolean b) {
 460         //PENDING: specify that string not painted when in indeterminate mode?
 461         //         or just leave that to the L&F?
 462         boolean oldValue = paintString;
 463         paintString = b;
 464         firePropertyChange("stringPainted", oldValue, paintString);
 465         if (paintString != oldValue) {
 466             revalidate();
 467             repaint();
 468         }
 469     }
 470 
 471 
 472     /**
 473      * Returns a {@code String} representation of the current progress.
 474      * By default, this returns a simple percentage {@code String} based on
 475      * the value returned from {@code getPercentComplete}.  An example
 476      * would be the "42%".  You can change this by calling {@code setString}.
 477      *
 478      * @return the value of the progress string, or a simple percentage string
 479      *         if the progress string is {@code null}
 480      * @see    #setString
 481      */
 482     public String getString(){
 483         if (progressString != null) {
 484             return progressString;
 485         } else {
 486             if (format == null) {
 487                 format = NumberFormat.getPercentInstance();
 488             }
 489             return format.format(new Double(getPercentComplete()));
 490         }
 491     }
 492 
 493     /**
 494      * Sets the value of the progress string. By default,
 495      * this string is <code>null</code>, implying the built-in behavior of
 496      * using a simple percent string.
 497      * If you have provided a custom progress string and want to revert to
 498      * the built-in behavior, set the string back to <code>null</code>.
 499      * <p>
 500      * The progress string is painted only if
 501      * the <code>isStringPainted</code> method returns <code>true</code>.
 502      *
 503      * @param  s       the value of the progress string
 504      * @see    #getString
 505      * @see    #setStringPainted
 506      * @see    #isStringPainted
 507      * @beaninfo
 508      *        bound: true
 509      *    attribute: visualUpdate true
 510      *  description: Specifies the progress string to paint
 511      */
 512     public void setString(String s){
 513         String oldValue = progressString;
 514         progressString = s;
 515         firePropertyChange("string", oldValue, progressString);
 516         if (progressString == null || oldValue == null || !progressString.equals(oldValue)) {
 517             repaint();
 518         }
 519     }
 520 
 521     /**
 522      * Returns the percent complete for the progress bar.
 523      * Note that this number is between 0.0 and 1.0.
 524      *
 525      * @return the percent complete for this progress bar
 526      */
 527     public double getPercentComplete() {
 528         long span = model.getMaximum() - model.getMinimum();
 529         double currentValue = model.getValue();
 530         double pc = (currentValue - model.getMinimum()) / span;
 531         return pc;
 532     }
 533 
 534     /**
 535      * Returns the <code>borderPainted</code> property.
 536      *
 537      * @return the value of the <code>borderPainted</code> property
 538      * @see    #setBorderPainted
 539      * @beaninfo
 540      *  description: Does the progress bar paint its border
 541      */
 542     public boolean isBorderPainted() {
 543         return paintBorder;
 544     }
 545 
 546     /**
 547      * Sets the <code>borderPainted</code> property, which is
 548      * <code>true</code> if the progress bar should paint its border.
 549      * The default value for this property is <code>true</code>.
 550      * Some look and feels might not implement painted borders;
 551      * they will ignore this property.
 552      *
 553      * @param   b       <code>true</code> if the progress bar
 554      *                  should paint its border;
 555      *                  otherwise, <code>false</code>
 556      * @see     #isBorderPainted
 557      * @beaninfo
 558      *        bound: true
 559      *    attribute: visualUpdate true
 560      *  description: Whether the progress bar should paint its border.
 561      */
 562     public void setBorderPainted(boolean b) {
 563         boolean oldValue = paintBorder;
 564         paintBorder = b;
 565         firePropertyChange("borderPainted", oldValue, paintBorder);
 566         if (paintBorder != oldValue) {
 567             repaint();
 568         }
 569     }
 570 
 571     /**
 572      * Paints the progress bar's border if the <code>borderPainted</code>
 573      * property is <code>true</code>.
 574      *
 575      * @param g  the <code>Graphics</code> context within which to paint the border
 576      * @see #paint
 577      * @see #setBorder
 578      * @see #isBorderPainted
 579      * @see #setBorderPainted
 580      */
 581     protected void paintBorder(Graphics g) {
 582         if (isBorderPainted()) {
 583             super.paintBorder(g);
 584         }
 585     }
 586 
 587 
 588     /**
 589      * Returns the look-and-feel object that renders this component.
 590      *
 591      * @return the <code>ProgressBarUI</code> object that renders this component
 592      */
 593     public ProgressBarUI getUI() {
 594         return (ProgressBarUI)ui;
 595     }
 596 
 597     /**
 598      * Sets the look-and-feel object that renders this component.
 599      *
 600      * @param ui  a <code>ProgressBarUI</code> object
 601      * @see UIDefaults#getUI
 602      * @beaninfo
 603      *        bound: true
 604      *       hidden: true
 605      *    attribute: visualUpdate true
 606      *  description: The UI object that implements the Component's LookAndFeel.
 607      */
 608     public void setUI(ProgressBarUI ui) {
 609         super.setUI(ui);
 610     }
 611 
 612 
 613     /**
 614      * Resets the UI property to a value from the current look and feel.
 615      *
 616      * @see JComponent#updateUI
 617      */
 618     public void updateUI() {
 619         setUI((ProgressBarUI)UIManager.getUI(this));
 620     }
 621 
 622 
 623     /**
 624      * Returns the name of the look-and-feel class that renders this component.
 625      *
 626      * @return the string "ProgressBarUI"
 627      * @see JComponent#getUIClassID
 628      * @see UIDefaults#getUI
 629      * @beaninfo
 630      *        expert: true
 631      *   description: A string that specifies the name of the look-and-feel class.
 632      */
 633     public String getUIClassID() {
 634         return uiClassID;
 635     }
 636 
 637 
 638     /* We pass each Change event to the listeners with the
 639      * the progress bar as the event source.
 640      * <p>
 641      * <strong>Warning:</strong>
 642      * Serialized objects of this class will not be compatible with
 643      * future Swing releases. The current serialization support is
 644      * appropriate for short term storage or RMI between applications running
 645      * the same version of Swing.  As of 1.4, support for long term storage
 646      * of all JavaBeans<sup><font size="-2">TM</font></sup>
 647      * has been added to the <code>java.beans</code> package.
 648      * Please see {@link java.beans.XMLEncoder}.
 649      */
 650     private class ModelListener implements ChangeListener, Serializable {
 651         public void stateChanged(ChangeEvent e) {
 652             fireStateChanged();
 653         }
 654     }
 655 
 656     /**
 657      * Subclasses that want to handle change events
 658      * from the model differently
 659      * can override this to return
 660      * an instance of a custom <code>ChangeListener</code> implementation.
 661      * The default {@code ChangeListener} simply calls the
 662      * {@code fireStateChanged} method to forward {@code ChangeEvent}s
 663      * to the {@code ChangeListener}s that have been added directly to the
 664      * progress bar.
 665      *
 666      * @see #changeListener
 667      * @see #fireStateChanged
 668      * @see javax.swing.event.ChangeListener
 669      * @see javax.swing.BoundedRangeModel
 670      */
 671     protected ChangeListener createChangeListener() {
 672         return new ModelListener();
 673     }
 674 
 675     /**
 676      * Adds the specified <code>ChangeListener</code> to the progress bar.
 677      *
 678      * @param l the <code>ChangeListener</code> to add
 679      */
 680     public void addChangeListener(ChangeListener l) {
 681         listenerList.add(ChangeListener.class, l);
 682     }
 683 
 684     /**
 685      * Removes a <code>ChangeListener</code> from the progress bar.
 686      *
 687      * @param l the <code>ChangeListener</code> to remove
 688      */
 689     public void removeChangeListener(ChangeListener l) {
 690         listenerList.remove(ChangeListener.class, l);
 691     }
 692 
 693     /**
 694      * Returns an array of all the <code>ChangeListener</code>s added
 695      * to this progress bar with <code>addChangeListener</code>.
 696      *
 697      * @return all of the <code>ChangeListener</code>s added or an empty
 698      *         array if no listeners have been added
 699      * @since 1.4
 700      */
 701     public ChangeListener[] getChangeListeners() {
 702         return (ChangeListener[])listenerList.getListeners(
 703                 ChangeListener.class);
 704     }
 705 
 706     /**
 707      * Send a {@code ChangeEvent}, whose source is this {@code JProgressBar}, to
 708      * all {@code ChangeListener}s that have registered interest in
 709      * {@code ChangeEvent}s.
 710      * This method is called each time a {@code ChangeEvent} is received from
 711      * the model.
 712      * <p>
 713      *
 714      * The event instance is created if necessary, and stored in
 715      * {@code changeEvent}.
 716      *
 717      * @see #addChangeListener
 718      * @see EventListenerList
 719      */
 720     protected void fireStateChanged() {
 721         // Guaranteed to return a non-null array
 722         Object[] listeners = listenerList.getListenerList();
 723         // Process the listeners last to first, notifying
 724         // those that are interested in this event
 725         for (int i = listeners.length-2; i>=0; i-=2) {
 726             if (listeners[i]==ChangeListener.class) {
 727                 // Lazily create the event:
 728                 if (changeEvent == null)
 729                     changeEvent = new ChangeEvent(this);
 730                 ((ChangeListener)listeners[i+1]).stateChanged(changeEvent);
 731             }
 732         }
 733     }
 734 
 735     /**
 736      * Returns the data model used by this progress bar.
 737      *
 738      * @return the <code>BoundedRangeModel</code> currently in use
 739      * @see #setModel
 740      * @see    BoundedRangeModel
 741      */
 742     public BoundedRangeModel getModel() {
 743         return model;
 744     }
 745 
 746     /**
 747      * Sets the data model used by the <code>JProgressBar</code>.
 748      * Note that the {@code BoundedRangeModel}'s {@code extent} is not used,
 749      * and is set to {@code 0}.
 750      *
 751      * @param  newModel the <code>BoundedRangeModel</code> to use
 752      *
 753      * @beaninfo
 754      *    expert: true
 755      * description: The data model used by the JProgressBar.
 756      */
 757     public void setModel(BoundedRangeModel newModel) {
 758         // PENDING(???) setting the same model to multiple bars is broken; listeners
 759         BoundedRangeModel oldModel = getModel();
 760 
 761         if (newModel != oldModel) {
 762             if (oldModel != null) {
 763                 oldModel.removeChangeListener(changeListener);
 764                 changeListener = null;
 765             }
 766 
 767             model = newModel;
 768 
 769             if (newModel != null) {
 770                 changeListener = createChangeListener();
 771                 newModel.addChangeListener(changeListener);
 772             }
 773 
 774             if (accessibleContext != null) {
 775                 accessibleContext.firePropertyChange(
 776                         AccessibleContext.ACCESSIBLE_VALUE_PROPERTY,
 777                         (oldModel== null
 778                          ? null : new Integer(oldModel.getValue())),
 779                         (newModel== null
 780                          ? null : new Integer(newModel.getValue())));
 781             }
 782 
 783             if (model != null) {
 784                 model.setExtent(0);
 785             }
 786             repaint();
 787         }
 788     }
 789 
 790 
 791     /* All of the model methods are implemented by delegation. */
 792 
 793     /**
 794      * Returns the progress bar's current {@code value}
 795      * from the <code>BoundedRangeModel</code>.
 796      * The value is always between the
 797      * minimum and maximum values, inclusive.
 798      *
 799      * @return  the current value of the progress bar
 800      * @see     #setValue
 801      * @see     BoundedRangeModel#getValue
 802      */
 803     public int getValue() { return getModel().getValue(); }
 804 
 805     /**
 806      * Returns the progress bar's {@code minimum} value
 807      * from the <code>BoundedRangeModel</code>.
 808      *
 809      * @return  the progress bar's minimum value
 810      * @see     #setMinimum
 811      * @see     BoundedRangeModel#getMinimum
 812      */
 813     public int getMinimum() { return getModel().getMinimum(); }
 814 
 815     /**
 816      * Returns the progress bar's {@code maximum} value
 817      * from the <code>BoundedRangeModel</code>.
 818      *
 819      * @return  the progress bar's maximum value
 820      * @see     #setMaximum
 821      * @see     BoundedRangeModel#getMaximum
 822      */
 823     public int getMaximum() { return getModel().getMaximum(); }
 824 
 825     /**
 826      * Sets the progress bar's current value to {@code n}.  This method
 827      * forwards the new value to the model.
 828      * <p>
 829      * The data model (an instance of {@code BoundedRangeModel})
 830      * handles any mathematical
 831      * issues arising from assigning faulty values.  See the
 832      * {@code BoundedRangeModel} documentation for details.
 833      * <p>
 834      * If the new value is different from the previous value,
 835      * all change listeners are notified.
 836      *
 837      * @param   n       the new value
 838      * @see     #getValue
 839      * @see     #addChangeListener
 840      * @see     BoundedRangeModel#setValue
 841      * @beaninfo
 842      *    preferred: true
 843      *  description: The progress bar's current value.
 844      */
 845     public void setValue(int n) {
 846         BoundedRangeModel brm = getModel();
 847         int oldValue = brm.getValue();
 848         brm.setValue(n);
 849 
 850         if (accessibleContext != null) {
 851             accessibleContext.firePropertyChange(
 852                     AccessibleContext.ACCESSIBLE_VALUE_PROPERTY,
 853                     new Integer(oldValue),
 854                     new Integer(brm.getValue()));
 855         }
 856     }
 857 
 858     /**
 859      * Sets the progress bar's minimum value
 860      * (stored in the progress bar's data model) to <code>n</code>.
 861      * <p>
 862      * The data model (a <code>BoundedRangeModel</code> instance)
 863      * handles any mathematical
 864      * issues arising from assigning faulty values.
 865      * See the {@code BoundedRangeModel} documentation for details.
 866      * <p>
 867      * If the minimum value is different from the previous minimum,
 868      * all change listeners are notified.
 869      *
 870      * @param  n       the new minimum
 871      * @see    #getMinimum
 872      * @see    #addChangeListener
 873      * @see    BoundedRangeModel#setMinimum
 874      * @beaninfo
 875      *  preferred: true
 876      * description: The progress bar's minimum value.
 877      */
 878     public void setMinimum(int n) { getModel().setMinimum(n); }
 879 
 880     /**
 881      * Sets the progress bar's maximum value
 882      * (stored in the progress bar's data model) to <code>n</code>.
 883      * <p>
 884      * The underlying <code>BoundedRangeModel</code> handles any mathematical
 885      * issues arising from assigning faulty values.
 886      * See the {@code BoundedRangeModel} documentation for details.
 887      * <p>
 888      * If the maximum value is different from the previous maximum,
 889      * all change listeners are notified.
 890      *
 891      * @param  n       the new maximum
 892      * @see    #getMaximum
 893      * @see    #addChangeListener
 894      * @see    BoundedRangeModel#setMaximum
 895      * @beaninfo
 896      *    preferred: true
 897      *  description: The progress bar's maximum value.
 898      */
 899     public void setMaximum(int n) { getModel().setMaximum(n); }
 900 
 901     /**
 902      * Sets the <code>indeterminate</code> property of the progress bar,
 903      * which determines whether the progress bar is in determinate
 904      * or indeterminate mode.
 905      * An indeterminate progress bar continuously displays animation
 906      * indicating that an operation of unknown length is occurring.
 907      * By default, this property is <code>false</code>.
 908      * Some look and feels might not support indeterminate progress bars;
 909      * they will ignore this property.
 910      *
 911      * <p>
 912      *
 913      * See
 914      * <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/progress.html" target="_top">How to Monitor Progress</a>
 915      * for examples of using indeterminate progress bars.
 916      *
 917      * @param newValue  <code>true</code> if the progress bar
 918      *                  should change to indeterminate mode;
 919      *                  <code>false</code> if it should revert to normal.
 920      *
 921      * @see #isIndeterminate
 922      * @see javax.swing.plaf.basic.BasicProgressBarUI
 923      *
 924      * @since 1.4
 925      *
 926      * @beaninfo
 927      *        bound: true
 928      *    attribute: visualUpdate true
 929      *  description: Set whether the progress bar is indeterminate (true)
 930      *               or normal (false).
 931      */
 932     public void setIndeterminate(boolean newValue) {
 933         boolean oldValue = indeterminate;
 934         indeterminate = newValue;
 935         firePropertyChange("indeterminate", oldValue, indeterminate);
 936     }
 937 
 938     /**
 939      * Returns the value of the <code>indeterminate</code> property.
 940      *
 941      * @return the value of the <code>indeterminate</code> property
 942      * @see    #setIndeterminate
 943      *
 944      * @since 1.4
 945      *
 946      * @beaninfo
 947      *  description: Is the progress bar indeterminate (true)
 948      *               or normal (false)?
 949      */
 950     public boolean isIndeterminate() {
 951         return indeterminate;
 952     }
 953 
 954 
 955     /**
 956      * See readObject() and writeObject() in JComponent for more
 957      * information about serialization in Swing.
 958      */
 959     private void writeObject(ObjectOutputStream s) throws IOException {
 960         s.defaultWriteObject();
 961         if (getUIClassID().equals(uiClassID)) {
 962             byte count = JComponent.getWriteObjCounter(this);
 963             JComponent.setWriteObjCounter(this, --count);
 964             if (count == 0 && ui != null) {
 965                 ui.installUI(this);
 966             }
 967         }
 968     }
 969 
 970 
 971     /**
 972      * Returns a string representation of this <code>JProgressBar</code>.
 973      * This method is intended to be used only for debugging purposes. The
 974      * content and format of the returned string may vary between
 975      * implementations. The returned string may be empty but may not
 976      * be <code>null</code>.
 977      *
 978      * @return  a string representation of this <code>JProgressBar</code>
 979      */
 980     protected String paramString() {
 981         String orientationString = (orientation == HORIZONTAL ?
 982                                     "HORIZONTAL" : "VERTICAL");
 983         String paintBorderString = (paintBorder ?
 984                                     "true" : "false");
 985         String progressStringString = (progressString != null ?
 986                                        progressString : "");
 987         String paintStringString = (paintString ?
 988                                     "true" : "false");
 989         String indeterminateString = (indeterminate ?
 990                                     "true" : "false");
 991 
 992         return super.paramString() +
 993         ",orientation=" + orientationString +
 994         ",paintBorder=" + paintBorderString +
 995         ",paintString=" + paintStringString +
 996         ",progressString=" + progressStringString +
 997         ",indeterminateString=" + indeterminateString;
 998     }
 999 
1000 /////////////////
1001 // Accessibility support
1002 ////////////////
1003 
1004     /**
1005      * Gets the <code>AccessibleContext</code> associated with this
1006      * <code>JProgressBar</code>. For progress bars, the
1007      * <code>AccessibleContext</code> takes the form of an
1008      * <code>AccessibleJProgressBar</code>.
1009      * A new <code>AccessibleJProgressBar</code> instance is created if necessary.
1010      *
1011      * @return an <code>AccessibleJProgressBar</code> that serves as the
1012      *         <code>AccessibleContext</code> of this <code>JProgressBar</code>
1013      * @beaninfo
1014      *       expert: true
1015      *  description: The AccessibleContext associated with this ProgressBar.
1016      */
1017     public AccessibleContext getAccessibleContext() {
1018         if (accessibleContext == null) {
1019             accessibleContext = new AccessibleJProgressBar();
1020         }
1021         return accessibleContext;
1022     }
1023 
1024     /**
1025      * This class implements accessibility support for the
1026      * <code>JProgressBar</code> class.  It provides an implementation of the
1027      * Java Accessibility API appropriate to progress bar user-interface
1028      * elements.
1029      * <p>
1030      * <strong>Warning:</strong>
1031      * Serialized objects of this class will not be compatible with
1032      * future Swing releases. The current serialization support is
1033      * appropriate for short term storage or RMI between applications running
1034      * the same version of Swing.  As of 1.4, support for long term storage
1035      * of all JavaBeans<sup><font size="-2">TM</font></sup>
1036      * has been added to the <code>java.beans</code> package.
1037      * Please see {@link java.beans.XMLEncoder}.
1038      */
1039     protected class AccessibleJProgressBar extends AccessibleJComponent
1040         implements AccessibleValue {
1041 
1042         /**
1043          * Gets the state set of this object.
1044          *
1045          * @return an instance of AccessibleState containing the current state
1046          * of the object
1047          * @see AccessibleState
1048          */
1049         public AccessibleStateSet getAccessibleStateSet() {
1050             AccessibleStateSet states = super.getAccessibleStateSet();
1051             if (getModel().getValueIsAdjusting()) {
1052                 states.add(AccessibleState.BUSY);
1053             }
1054             if (getOrientation() == VERTICAL) {
1055                 states.add(AccessibleState.VERTICAL);
1056             } else {
1057                 states.add(AccessibleState.HORIZONTAL);
1058             }
1059             return states;
1060         }
1061 
1062         /**
1063          * Gets the role of this object.
1064          *
1065          * @return an instance of AccessibleRole describing the role of the
1066          * object
1067          */
1068         public AccessibleRole getAccessibleRole() {
1069             return AccessibleRole.PROGRESS_BAR;
1070         }
1071 
1072         /**
1073          * Gets the <code>AccessibleValue</code> associated with this object.  In the
1074          * implementation of the Java Accessibility API for this class,
1075          * returns this object, which is responsible for implementing the
1076          * <code>AccessibleValue</code> interface on behalf of itself.
1077          *
1078          * @return this object
1079          */
1080         public AccessibleValue getAccessibleValue() {
1081             return this;
1082         }
1083 
1084         /**
1085          * Gets the accessible value of this object.
1086          *
1087          * @return the current value of this object
1088          */
1089         public Number getCurrentAccessibleValue() {
1090             return new Integer(getValue());
1091         }
1092 
1093         /**
1094          * Sets the value of this object as a <code>Number</code>.
1095          *
1096          * @return <code>true</code> if the value was set
1097          */
1098         public boolean setCurrentAccessibleValue(Number n) {
1099             // TIGER- 4422535
1100             if (n == null) {
1101                 return false;
1102             }
1103             setValue(n.intValue());
1104             return true;
1105         }
1106 
1107         /**
1108          * Gets the minimum accessible value of this object.
1109          *
1110          * @return the minimum value of this object
1111          */
1112         public Number getMinimumAccessibleValue() {
1113             return new Integer(getMinimum());
1114         }
1115 
1116         /**
1117          * Gets the maximum accessible value of this object.
1118          *
1119          * @return the maximum value of this object
1120          */
1121         public Number getMaximumAccessibleValue() {
1122             // TIGER - 4422362
1123             return new Integer(model.getMaximum() - model.getExtent());
1124         }
1125 
1126     } // AccessibleJProgressBar
1127 }