1 /*
   2  * Copyright (c) 1997, 2008, 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://docs.oracle.com/javase/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&trade;
 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&trade;
 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 listenerList.getListeners(ChangeListener.class);
 703     }
 704 
 705     /**
 706      * Send a {@code ChangeEvent}, whose source is this {@code JProgressBar}, to
 707      * all {@code ChangeListener}s that have registered interest in
 708      * {@code ChangeEvent}s.
 709      * This method is called each time a {@code ChangeEvent} is received from
 710      * the model.
 711      * <p>
 712      *
 713      * The event instance is created if necessary, and stored in
 714      * {@code changeEvent}.
 715      *
 716      * @see #addChangeListener
 717      * @see EventListenerList
 718      */
 719     protected void fireStateChanged() {
 720         // Guaranteed to return a non-null array
 721         Object[] listeners = listenerList.getListenerList();
 722         // Process the listeners last to first, notifying
 723         // those that are interested in this event
 724         for (int i = listeners.length-2; i>=0; i-=2) {
 725             if (listeners[i]==ChangeListener.class) {
 726                 // Lazily create the event:
 727                 if (changeEvent == null)
 728                     changeEvent = new ChangeEvent(this);
 729                 ((ChangeListener)listeners[i+1]).stateChanged(changeEvent);
 730             }
 731         }
 732     }
 733 
 734     /**
 735      * Returns the data model used by this progress bar.
 736      *
 737      * @return the <code>BoundedRangeModel</code> currently in use
 738      * @see #setModel
 739      * @see    BoundedRangeModel
 740      */
 741     public BoundedRangeModel getModel() {
 742         return model;
 743     }
 744 
 745     /**
 746      * Sets the data model used by the <code>JProgressBar</code>.
 747      * Note that the {@code BoundedRangeModel}'s {@code extent} is not used,
 748      * and is set to {@code 0}.
 749      *
 750      * @param  newModel the <code>BoundedRangeModel</code> to use
 751      *
 752      * @beaninfo
 753      *    expert: true
 754      * description: The data model used by the JProgressBar.
 755      */
 756     public void setModel(BoundedRangeModel newModel) {
 757         // PENDING(???) setting the same model to multiple bars is broken; listeners
 758         BoundedRangeModel oldModel = getModel();
 759 
 760         if (newModel != oldModel) {
 761             if (oldModel != null) {
 762                 oldModel.removeChangeListener(changeListener);
 763                 changeListener = null;
 764             }
 765 
 766             model = newModel;
 767 
 768             if (newModel != null) {
 769                 changeListener = createChangeListener();
 770                 newModel.addChangeListener(changeListener);
 771             }
 772 
 773             if (accessibleContext != null) {
 774                 accessibleContext.firePropertyChange(
 775                         AccessibleContext.ACCESSIBLE_VALUE_PROPERTY,
 776                         (oldModel== null
 777                          ? null : Integer.valueOf(oldModel.getValue())),
 778                         (newModel== null
 779                          ? null : Integer.valueOf(newModel.getValue())));
 780             }
 781 
 782             if (model != null) {
 783                 model.setExtent(0);
 784             }
 785             repaint();
 786         }
 787     }
 788 
 789 
 790     /* All of the model methods are implemented by delegation. */
 791 
 792     /**
 793      * Returns the progress bar's current {@code value}
 794      * from the <code>BoundedRangeModel</code>.
 795      * The value is always between the
 796      * minimum and maximum values, inclusive.
 797      *
 798      * @return  the current value of the progress bar
 799      * @see     #setValue
 800      * @see     BoundedRangeModel#getValue
 801      */
 802     public int getValue() { return getModel().getValue(); }
 803 
 804     /**
 805      * Returns the progress bar's {@code minimum} value
 806      * from the <code>BoundedRangeModel</code>.
 807      *
 808      * @return  the progress bar's minimum value
 809      * @see     #setMinimum
 810      * @see     BoundedRangeModel#getMinimum
 811      */
 812     public int getMinimum() { return getModel().getMinimum(); }
 813 
 814     /**
 815      * Returns the progress bar's {@code maximum} value
 816      * from the <code>BoundedRangeModel</code>.
 817      *
 818      * @return  the progress bar's maximum value
 819      * @see     #setMaximum
 820      * @see     BoundedRangeModel#getMaximum
 821      */
 822     public int getMaximum() { return getModel().getMaximum(); }
 823 
 824     /**
 825      * Sets the progress bar's current value to {@code n}.  This method
 826      * forwards the new value to the model.
 827      * <p>
 828      * The data model (an instance of {@code BoundedRangeModel})
 829      * handles any mathematical
 830      * issues arising from assigning faulty values.  See the
 831      * {@code BoundedRangeModel} documentation for details.
 832      * <p>
 833      * If the new value is different from the previous value,
 834      * all change listeners are notified.
 835      *
 836      * @param   n       the new value
 837      * @see     #getValue
 838      * @see     #addChangeListener
 839      * @see     BoundedRangeModel#setValue
 840      * @beaninfo
 841      *    preferred: true
 842      *  description: The progress bar's current value.
 843      */
 844     public void setValue(int n) {
 845         BoundedRangeModel brm = getModel();
 846         int oldValue = brm.getValue();
 847         brm.setValue(n);
 848 
 849         if (accessibleContext != null) {
 850             accessibleContext.firePropertyChange(
 851                     AccessibleContext.ACCESSIBLE_VALUE_PROPERTY,
 852                     Integer.valueOf(oldValue),
 853                     Integer.valueOf(brm.getValue()));
 854         }
 855     }
 856 
 857     /**
 858      * Sets the progress bar's minimum value
 859      * (stored in the progress bar's data model) to <code>n</code>.
 860      * <p>
 861      * The data model (a <code>BoundedRangeModel</code> instance)
 862      * handles any mathematical
 863      * issues arising from assigning faulty values.
 864      * See the {@code BoundedRangeModel} documentation for details.
 865      * <p>
 866      * If the minimum value is different from the previous minimum,
 867      * all change listeners are notified.
 868      *
 869      * @param  n       the new minimum
 870      * @see    #getMinimum
 871      * @see    #addChangeListener
 872      * @see    BoundedRangeModel#setMinimum
 873      * @beaninfo
 874      *  preferred: true
 875      * description: The progress bar's minimum value.
 876      */
 877     public void setMinimum(int n) { getModel().setMinimum(n); }
 878 
 879     /**
 880      * Sets the progress bar's maximum value
 881      * (stored in the progress bar's data model) to <code>n</code>.
 882      * <p>
 883      * The underlying <code>BoundedRangeModel</code> handles any mathematical
 884      * issues arising from assigning faulty values.
 885      * See the {@code BoundedRangeModel} documentation for details.
 886      * <p>
 887      * If the maximum value is different from the previous maximum,
 888      * all change listeners are notified.
 889      *
 890      * @param  n       the new maximum
 891      * @see    #getMaximum
 892      * @see    #addChangeListener
 893      * @see    BoundedRangeModel#setMaximum
 894      * @beaninfo
 895      *    preferred: true
 896      *  description: The progress bar's maximum value.
 897      */
 898     public void setMaximum(int n) { getModel().setMaximum(n); }
 899 
 900     /**
 901      * Sets the <code>indeterminate</code> property of the progress bar,
 902      * which determines whether the progress bar is in determinate
 903      * or indeterminate mode.
 904      * An indeterminate progress bar continuously displays animation
 905      * indicating that an operation of unknown length is occurring.
 906      * By default, this property is <code>false</code>.
 907      * Some look and feels might not support indeterminate progress bars;
 908      * they will ignore this property.
 909      *
 910      * <p>
 911      *
 912      * See
 913      * <a href="http://docs.oracle.com/javase/tutorial/uiswing/components/progress.html" target="_top">How to Monitor Progress</a>
 914      * for examples of using indeterminate progress bars.
 915      *
 916      * @param newValue  <code>true</code> if the progress bar
 917      *                  should change to indeterminate mode;
 918      *                  <code>false</code> if it should revert to normal.
 919      *
 920      * @see #isIndeterminate
 921      * @see javax.swing.plaf.basic.BasicProgressBarUI
 922      *
 923      * @since 1.4
 924      *
 925      * @beaninfo
 926      *        bound: true
 927      *    attribute: visualUpdate true
 928      *  description: Set whether the progress bar is indeterminate (true)
 929      *               or normal (false).
 930      */
 931     public void setIndeterminate(boolean newValue) {
 932         boolean oldValue = indeterminate;
 933         indeterminate = newValue;
 934         firePropertyChange("indeterminate", oldValue, indeterminate);
 935     }
 936 
 937     /**
 938      * Returns the value of the <code>indeterminate</code> property.
 939      *
 940      * @return the value of the <code>indeterminate</code> property
 941      * @see    #setIndeterminate
 942      *
 943      * @since 1.4
 944      *
 945      * @beaninfo
 946      *  description: Is the progress bar indeterminate (true)
 947      *               or normal (false)?
 948      */
 949     public boolean isIndeterminate() {
 950         return indeterminate;
 951     }
 952 
 953 
 954     /**
 955      * See readObject() and writeObject() in JComponent for more
 956      * information about serialization in Swing.
 957      */
 958     private void writeObject(ObjectOutputStream s) throws IOException {
 959         s.defaultWriteObject();
 960         if (getUIClassID().equals(uiClassID)) {
 961             byte count = JComponent.getWriteObjCounter(this);
 962             JComponent.setWriteObjCounter(this, --count);
 963             if (count == 0 && ui != null) {
 964                 ui.installUI(this);
 965             }
 966         }
 967     }
 968 
 969 
 970     /**
 971      * Returns a string representation of this <code>JProgressBar</code>.
 972      * This method is intended to be used only for debugging purposes. The
 973      * content and format of the returned string may vary between
 974      * implementations. The returned string may be empty but may not
 975      * be <code>null</code>.
 976      *
 977      * @return  a string representation of this <code>JProgressBar</code>
 978      */
 979     protected String paramString() {
 980         String orientationString = (orientation == HORIZONTAL ?
 981                                     "HORIZONTAL" : "VERTICAL");
 982         String paintBorderString = (paintBorder ?
 983                                     "true" : "false");
 984         String progressStringString = (progressString != null ?
 985                                        progressString : "");
 986         String paintStringString = (paintString ?
 987                                     "true" : "false");
 988         String indeterminateString = (indeterminate ?
 989                                     "true" : "false");
 990 
 991         return super.paramString() +
 992         ",orientation=" + orientationString +
 993         ",paintBorder=" + paintBorderString +
 994         ",paintString=" + paintStringString +
 995         ",progressString=" + progressStringString +
 996         ",indeterminateString=" + indeterminateString;
 997     }
 998 
 999 /////////////////
1000 // Accessibility support
1001 ////////////////
1002 
1003     /**
1004      * Gets the <code>AccessibleContext</code> associated with this
1005      * <code>JProgressBar</code>. For progress bars, the
1006      * <code>AccessibleContext</code> takes the form of an
1007      * <code>AccessibleJProgressBar</code>.
1008      * A new <code>AccessibleJProgressBar</code> instance is created if necessary.
1009      *
1010      * @return an <code>AccessibleJProgressBar</code> that serves as the
1011      *         <code>AccessibleContext</code> of this <code>JProgressBar</code>
1012      * @beaninfo
1013      *       expert: true
1014      *  description: The AccessibleContext associated with this ProgressBar.
1015      */
1016     public AccessibleContext getAccessibleContext() {
1017         if (accessibleContext == null) {
1018             accessibleContext = new AccessibleJProgressBar();
1019         }
1020         return accessibleContext;
1021     }
1022 
1023     /**
1024      * This class implements accessibility support for the
1025      * <code>JProgressBar</code> class.  It provides an implementation of the
1026      * Java Accessibility API appropriate to progress bar user-interface
1027      * elements.
1028      * <p>
1029      * <strong>Warning:</strong>
1030      * Serialized objects of this class will not be compatible with
1031      * future Swing releases. The current serialization support is
1032      * appropriate for short term storage or RMI between applications running
1033      * the same version of Swing.  As of 1.4, support for long term storage
1034      * of all JavaBeans&trade;
1035      * has been added to the <code>java.beans</code> package.
1036      * Please see {@link java.beans.XMLEncoder}.
1037      */
1038     protected class AccessibleJProgressBar extends AccessibleJComponent
1039         implements AccessibleValue {
1040 
1041         /**
1042          * Gets the state set of this object.
1043          *
1044          * @return an instance of AccessibleState containing the current state
1045          * of the object
1046          * @see AccessibleState
1047          */
1048         public AccessibleStateSet getAccessibleStateSet() {
1049             AccessibleStateSet states = super.getAccessibleStateSet();
1050             if (getModel().getValueIsAdjusting()) {
1051                 states.add(AccessibleState.BUSY);
1052             }
1053             if (getOrientation() == VERTICAL) {
1054                 states.add(AccessibleState.VERTICAL);
1055             } else {
1056                 states.add(AccessibleState.HORIZONTAL);
1057             }
1058             return states;
1059         }
1060 
1061         /**
1062          * Gets the role of this object.
1063          *
1064          * @return an instance of AccessibleRole describing the role of the
1065          * object
1066          */
1067         public AccessibleRole getAccessibleRole() {
1068             return AccessibleRole.PROGRESS_BAR;
1069         }
1070 
1071         /**
1072          * Gets the <code>AccessibleValue</code> associated with this object.  In the
1073          * implementation of the Java Accessibility API for this class,
1074          * returns this object, which is responsible for implementing the
1075          * <code>AccessibleValue</code> interface on behalf of itself.
1076          *
1077          * @return this object
1078          */
1079         public AccessibleValue getAccessibleValue() {
1080             return this;
1081         }
1082 
1083         /**
1084          * Gets the accessible value of this object.
1085          *
1086          * @return the current value of this object
1087          */
1088         public Number getCurrentAccessibleValue() {
1089             return Integer.valueOf(getValue());
1090         }
1091 
1092         /**
1093          * Sets the value of this object as a <code>Number</code>.
1094          *
1095          * @return <code>true</code> if the value was set
1096          */
1097         public boolean setCurrentAccessibleValue(Number n) {
1098             // TIGER- 4422535
1099             if (n == null) {
1100                 return false;
1101             }
1102             setValue(n.intValue());
1103             return true;
1104         }
1105 
1106         /**
1107          * Gets the minimum accessible value of this object.
1108          *
1109          * @return the minimum value of this object
1110          */
1111         public Number getMinimumAccessibleValue() {
1112             return Integer.valueOf(getMinimum());
1113         }
1114 
1115         /**
1116          * Gets the maximum accessible value of this object.
1117          *
1118          * @return the maximum value of this object
1119          */
1120         public Number getMaximumAccessibleValue() {
1121             // TIGER - 4422362
1122             return Integer.valueOf(model.getMaximum() - model.getExtent());
1123         }
1124 
1125     } // AccessibleJProgressBar
1126 }