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