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