1/*
2 * Copyright (c) 1997, 2015, 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 */
25package javax.swing;
26
27import java.awt.Graphics;
28import java.beans.JavaBean;
29import java.beans.BeanProperty;
30
31import java.text.Format;
32import java.text.NumberFormat;
33
34import java.io.Serializable;
35import java.io.ObjectOutputStream;
36import java.io.IOException;
37
38import javax.swing.event.*;
39import javax.accessibility.*;
40import 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
130public 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    private static final int defaultMinimum = 0;
190    /**
191     * The default maximum for a progress bar is 100.
192     */
193    private static final int defaultMaximum = 100;
194    /**
195     * The default orientation for a progress bar is <code>HORIZONTAL</code>.
196     */
197    private static final 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 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(Double.valueOf(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}
1100