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