1 /* JProgressBar.java --
2    Copyright (C) 2002, 2004, 2005, 2006  Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 
39 package javax.swing;
40 
41 import gnu.java.lang.CPStringBuilder;
42 
43 import java.awt.Graphics;
44 import java.beans.PropertyChangeEvent;
45 
46 import javax.accessibility.Accessible;
47 import javax.accessibility.AccessibleContext;
48 import javax.accessibility.AccessibleRole;
49 import javax.accessibility.AccessibleState;
50 import javax.accessibility.AccessibleStateSet;
51 import javax.accessibility.AccessibleValue;
52 import javax.swing.border.Border;
53 import javax.swing.event.ChangeEvent;
54 import javax.swing.event.ChangeListener;
55 import javax.swing.plaf.ProgressBarUI;
56 
57 /**
58  * A component that displays a visual indicator of the progress of a task. The
59  * component has two modes: determinate and indeterminate.  In determinate mode,
60  * the <code>JProgressBar</code> fills a percentage of its bar based on its
61  * current value. In indeterminate mode, it creates box and bounces it between
62  * its bounds.
63  * <p>
64  * This component has the following properties:
65  * </p>
66  * <table>
67  * <tr><th> Property         </th><th> Stored in   </th><th> Bound? </th></tr>
68  * <tr><td> borderPainted    </td><td> progressBar </td><td> yes    </td></tr>
69  * <tr><td> changeListeners  </td><td> progressBar </td><td> no     </td></tr>
70  * <tr><td> indeterminate    </td><td> progressBar </td><td> yes    </td></tr>
71  * <tr><td> maximum          </td><td> model       </td><td> no     </td></tr>
72  * <tr><td> minimum          </td><td> model       </td><td> no     </td></tr>
73  * <tr><td> model            </td><td> progressBar </td><td> no     </td></tr>
74  * <tr><td> orientation      </td><td> progressBar </td><td> yes    </td></tr>
75  * <tr><td> percentComplete  </td><td> progressBar </td><td> no     </td></tr>
76  * <tr><td> string           </td><td> progressBar </td><td> yes    </td></tr>
77  * <tr><td> stringPainted    </td><td> progressBar </td><td> yes    </td></tr>
78  * <tr><td> value            </td><td> model       </td><td> no     </td></tr>
79  * </table>
80  */
81 public class JProgressBar extends JComponent implements SwingConstants,
82                                                         Accessible
83 {
84   /**
85    * Provides the accessibility features for the <code>JProgressBar</code>
86    * component.
87    */
88   protected class AccessibleJProgressBar extends AccessibleJComponent
89     implements AccessibleValue
90   {
91     private static final long serialVersionUID = -2938130009392721813L;
92 
93     /**
94      * Creates a new <code>AccessibleJProgressBar</code> instance.
95      */
AccessibleJProgressBar()96     protected AccessibleJProgressBar()
97     {
98       // Nothing to do here.
99     }
100 
101     /**
102      * Returns a set containing the current state of the {@link JProgressBar}
103      * component.
104      *
105      * @return The accessible state set.
106      */
getAccessibleStateSet()107     public AccessibleStateSet getAccessibleStateSet()
108     {
109       AccessibleStateSet result = super.getAccessibleStateSet();
110       if (orientation == JProgressBar.HORIZONTAL)
111         result.add(AccessibleState.HORIZONTAL);
112       else if (orientation == JProgressBar.VERTICAL)
113         result.add(AccessibleState.VERTICAL);
114       return result;
115     }
116 
117     /**
118      * Returns the accessible role for the <code>JProgressBar</code> component.
119      *
120      * @return {@link AccessibleRole#PROGRESS_BAR}.
121      */
getAccessibleRole()122     public AccessibleRole getAccessibleRole()
123     {
124       return AccessibleRole.PROGRESS_BAR;
125     }
126 
127     /**
128      * Returns an object that provides access to the current, minimum and
129      * maximum values.
130      *
131      * @return The accessible value.
132      */
getAccessibleValue()133     public AccessibleValue getAccessibleValue()
134     {
135       return this;
136     }
137 
138     /**
139      * Returns the current value of the {@link JProgressBar} component, as an
140      * {@link Integer}.
141      *
142      * @return The current value of the {@link JProgressBar} component.
143      */
getCurrentAccessibleValue()144     public Number getCurrentAccessibleValue()
145     {
146       return new Integer(getValue());
147     }
148 
149     /**
150      * Sets the current value of the {@link JProgressBar} component and sends a
151      * {@link PropertyChangeEvent} (with the property name
152      * {@link AccessibleContext#ACCESSIBLE_VALUE_PROPERTY}) to all registered
153      * listeners.  If the supplied value is <code>null</code>, this method
154      * does nothing and returns <code>false</code>.
155      *
156      * @param value  the new progress bar value (<code>null</code> permitted).
157      *
158      * @return <code>true</code> if the slider value is updated, and
159      *     <code>false</code> otherwise.
160      */
setCurrentAccessibleValue(Number value)161     public boolean setCurrentAccessibleValue(Number value)
162     {
163       if (value == null)
164         return false;
165       Number oldValue = getCurrentAccessibleValue();
166       setValue(value.intValue());
167       firePropertyChange(AccessibleContext.ACCESSIBLE_VALUE_PROPERTY, oldValue,
168                          new Integer(getValue()));
169       return true;
170     }
171 
172     /**
173      * Returns the minimum value of the {@link JProgressBar} component, as an
174      * {@link Integer}.
175      *
176      * @return The minimum value of the {@link JProgressBar} component.
177      */
getMinimumAccessibleValue()178     public Number getMinimumAccessibleValue()
179     {
180       return new Integer(getMinimum());
181     }
182 
183     /**
184      * Returns the maximum value of the {@link JProgressBar} component, as an
185      * {@link Integer}.
186      *
187      * @return The maximum value of the {@link JProgressBar} component.
188      */
getMaximumAccessibleValue()189     public Number getMaximumAccessibleValue()
190     {
191       return new Integer(getMaximum());
192     }
193   }
194 
195   private static final long serialVersionUID = 1980046021813598781L;
196 
197   /**
198    * A flag that determines the mode (<code>true</code> for indeterminate,
199    * <code>false</code> for determinate).
200    */
201   private transient boolean indeterminate = false;
202 
203   /**
204    * The orientation of the <code>JProgressBar</code>
205    * ({@link SwingConstants#HORIZONTAL} or {@link SwingConstants#VERTICAL}).
206    * Defaults to {@link SwingConstants#HORIZONTAL}.
207    * @see #setOrientation(int)
208    */
209   protected int orientation;
210 
211   /**
212    * A flag the controls whether or not the component's border is painted.
213    * The default is <code>true</code>.
214    * @see #setBorderPainted(boolean)
215    */
216   protected boolean paintBorder = true;
217 
218   /**
219    * The model defining the bounds and current value for the progress bar.
220    * @see #setModel(BoundedRangeModel)
221    */
222   protected BoundedRangeModel model;
223 
224   /**
225    * A custom string for display in the progress bar.  If this is
226    * <code>null</code>, a default string will be generated.
227    * @see #setString(String)
228    */
229   protected String progressString;
230 
231   /**
232    * A flag that controls whether a string is displayed within the progress
233    * bar.
234    * @see #setStringPainted(boolean)
235    */
236   protected boolean paintString = false;
237 
238   /**
239    * A single change event reused for all events.
240    * @see #fireStateChanged()
241    */
242   protected transient ChangeEvent changeEvent;
243 
244   /**
245    * The listener that is registered with the model. */
246   protected ChangeListener changeListener;
247 
248   /**
249    * Creates a new <code>JProgressBar</code> with default attributes.  The
250    * following defaults are used:
251    * <p>
252    * <ul>
253    * <li><code>value</code>: 0;</li>
254    * <li><code>minimum</code>: 0;</li>
255    * <li><code>maximum</code>: 100;</li>
256    * <li><code>orientation</code>: {@link SwingConstants#HORIZONTAL}.</li>
257    * </ul>
258    */
JProgressBar()259   public JProgressBar()
260   {
261     this(HORIZONTAL, 0, 100);
262   }
263 
264   /**
265    * Creates a new <code>JProgressBar</code> with the specified
266    * <code>orientation</code>.  The following defaults are used:
267    * <p>
268    * <ul>
269    * <li><code>value</code>: 0;</li>
270    * <li><code>minimum</code>: 0;</li>
271    * <li><code>maximum</code>: 100;</li>
272    * </ul>
273    *
274    * @param orientation  the orientation ({@link #HORIZONTAL} or
275    *     {@link #VERTICAL}).
276    *
277    * @throws IllegalArgumentException if <code>orientation</code> is not one of
278    *     the specified values.
279    */
JProgressBar(int orientation)280   public JProgressBar(int orientation)
281   {
282     this(orientation, 0, 100);
283   }
284 
285   /**
286    * Creates a new <code>JProgressBar</code> with the specified value range.
287    * The following defaults are used:
288    * <p>
289    * <ul>
290    * <li><code>value</code>: <code>minimum</code>;</li>
291    * <li><code>orientation</code>: {@link SwingConstants#HORIZONTAL}.</li>
292    * </ul>
293    *
294    * @param minimum  the lower bound of the value range.
295    * @param maximum  the upper bound of the value range.
296    */
JProgressBar(int minimum, int maximum)297   public JProgressBar(int minimum, int maximum)
298   {
299     this(HORIZONTAL, minimum, maximum);
300   }
301 
302   /**
303    * Creates a new <code>JProgressBar</code> with the specified range and
304    * orientation.  The following defaults are used:
305    * <p>
306    * <ul>
307    * <li><code>value</code>: <code>minimum</code>;</li>
308    * </ul>
309    *
310    * @param minimum  the lower bound of the value range.
311    * @param maximum  the upper bound of the value range.
312    * @param orientation  the orientation ({@link #HORIZONTAL} or
313    *     {@link #VERTICAL}).
314    *
315    * @throws IllegalArgumentException if <code>orientation</code> is not one of
316    *     the specified values.
317    */
JProgressBar(int orientation, int minimum, int maximum)318   public JProgressBar(int orientation, int minimum, int maximum)
319   {
320     model = new DefaultBoundedRangeModel(minimum, 0, minimum, maximum);
321     if (orientation != HORIZONTAL && orientation != VERTICAL)
322       throw new IllegalArgumentException(orientation
323                                          + " is not a legal orientation");
324     this.orientation = orientation;
325     changeListener = createChangeListener();
326     model.addChangeListener(changeListener);
327     updateUI();
328   }
329 
330   /**
331    * Creates a new <code>JProgressBar</code> with the specified model.  The
332    * following defaults are used:
333    * <p>
334    * <ul>
335    * <li><code>orientation</code>: {@link SwingConstants#HORIZONTAL}.</li>
336    * </ul>
337    *
338    * @param model  the model (<code>null</code> not permitted).
339    */
JProgressBar(BoundedRangeModel model)340   public JProgressBar(BoundedRangeModel model)
341   {
342     this.model = model;
343     changeListener = createChangeListener();
344     if (model != null)
345       model.addChangeListener(changeListener);
346     updateUI();
347   }
348 
349   /**
350    * Returns the current value for the <code>JProgressBar</code>.  This value
351    * is fetched from the model.
352    *
353    * @return The current value.
354    *
355    * @see #setValue(int)
356    */
getValue()357   public int getValue()
358   {
359     return model.getValue();
360   }
361 
362   /**
363    * Sets the current value for the <code>JProgressBar</code>.  The value is
364    * stored in the component's <code>model</code> (see {@link #getModel()}).
365    * If the new value is different to the old value, a {@link ChangeEvent} is
366    * sent to the model's registered listeners.  In turn, this triggers a call
367    * to {@link #fireStateChanged()} which will send a <code>ChangeEvent</code>
368    * to this component's registered listeners.
369    * <p>
370    * If <code>value</code> is outside the range <code>minimum</code> to
371    * <code>maximum</code>, it will be set to the nearest of those boundary
372    * values.
373    *
374    * @param value  the new value.
375    *
376    * @see #getValue()
377    */
setValue(int value)378   public void setValue(int value)
379   {
380     model.setValue(value);
381   }
382 
383   /**
384    * Paints the component's border, but only if {@link #isBorderPainted()}
385    * returns <code>true</code>.
386    *
387    * @param graphics  the graphics object to paint with.
388    *
389    * @see #setBorderPainted(boolean)
390    */
paintBorder(Graphics graphics)391   protected void paintBorder(Graphics graphics)
392   {
393     Border border = getBorder();
394     if (paintBorder && border != null)
395       border.paintBorder(this, graphics, 0, 0, getWidth(), getHeight());
396   }
397 
398   /**
399    * Returns the orientation of the <code>JProgressBar</code> component, which
400    * is either {@link SwingConstants#HORIZONTAL} or
401    * {@link SwingConstants#VERTICAL}.  The default orientation is
402    * <code>HORIZONTAL</code>.
403    *
404    * @return The orientation.
405    *
406    * @see #setOrientation(int)
407    */
getOrientation()408   public int getOrientation()
409   {
410     return orientation;
411   }
412 
413   /**
414    * Sets the orientation for this <code>JProgressBar</code> component and,
415    * if the value changes, sends a {@link PropertyChangeEvent} (with the
416    * property name <code>"orientation"</code>) to all registered listeners.
417    *
418    * @param orientation  the orientation ({@link #HORIZONTAL} or
419    *     {@link #VERTICAL}).
420    *
421    * @throws IllegalArgumentException if <code>orientation</code> is not
422    *     one of the listed values.
423    *
424    * @see #getOrientation()
425    */
setOrientation(int orientation)426   public void setOrientation(int orientation)
427   {
428     if (orientation != VERTICAL && orientation != HORIZONTAL)
429       throw new IllegalArgumentException(orientation
430                                          + " is not a legal orientation");
431     if (this.orientation != orientation)
432       {
433         int oldOrientation = this.orientation;
434         this.orientation = orientation;
435         firePropertyChange("orientation", oldOrientation, this.orientation);
436       }
437   }
438 
439   /**
440    * Returns the flag that controls whether or not the string returned by
441    * {@link #getString()} is displayed by the <code>JProgressBar</code>
442    * component.
443    *
444    * @return <code>true</code> if the string should be displayed, and
445    *     <code>false</code> otherwise.
446    *
447    * @see #setStringPainted(boolean)
448    */
isStringPainted()449   public boolean isStringPainted()
450   {
451     return paintString;
452   }
453 
454   /**
455    * Sets the flag that controls whether or not the string returned by
456    * {@link #getString()} is displayed by the <code>JProgressBar</code>
457    * component.  If the flag value changes, a {@link PropertyChangeEvent} (with
458    * the property name <code>"stringPainted"</code>) is sent to all registered
459    * listeners.
460    *
461    * @param painted  the new flag value.
462    *
463    * @see #isStringPainted()
464    * @see #setString(String)
465    */
setStringPainted(boolean painted)466   public void setStringPainted(boolean painted)
467   {
468     if (paintString != painted)
469       {
470         boolean oldPainted = paintString;
471         paintString = painted;
472         firePropertyChange("stringPainted", oldPainted, paintString);
473       }
474   }
475 
476   /**
477    * Returns the string that is painted on the <code>JProgressBar</code> if
478    * {@link #isStringPainted()} returns <code>true</code>.  If no string has
479    * been explicitly set, this method will return a string displaying the
480    * value of {@link #getPercentComplete()}.
481    *
482    * @return The string.
483    *
484    * @see #setString(String)
485    * @see #setStringPainted(boolean)
486    */
getString()487   public String getString()
488   {
489     if (progressString != null)
490       return progressString;
491     else
492       return (int) (getPercentComplete() * 100) + "%";
493   }
494 
495   /**
496    * Sets the string to display within the progress bar and, if the new value
497    * is different to the old value, sends a {@link PropertyChangeEvent} (with
498    * the property name <code>"string"</code>) to all registered listeners. If
499    * the string is set to <code>null</code>, {@link #getString()} will return
500    * a default string.
501    *
502    * @param string  the string (<code>null</code> permitted).
503    *
504    * @see #getString()
505    * @see #setStringPainted(boolean)
506    */
setString(String string)507   public void setString(String string)
508   {
509     if (((string == null || progressString == null) &&
510         string != progressString) || (string != null &&
511         ! string.equals(progressString)))
512       {
513         String oldString = progressString;
514         progressString = string;
515         firePropertyChange("string", oldString, progressString);
516       }
517   }
518 
519   /**
520    * Returns the current value expressed as a percentage.  This is calculated
521    * as <code>(value - min) / (max - min)</code>.
522    *
523    * @return The percentage (a value in the range 0.0 to 1.0).
524    */
getPercentComplete()525   public double getPercentComplete()
526   {
527     if (getMaximum() == getMinimum())
528       return 1.0;
529     else
530       return (double) (model.getValue() - model.getMinimum())
531           / (model.getMaximum() - model.getMinimum());
532   }
533 
534   /**
535    * Returns a flag that controls whether or not the component's border is
536    * painted.  The default value is <code>true</code>.
537    *
538    * @return <code>true</code> if the component's border should be painted,
539    *     and <code>false</code> otherwise.
540    *
541    * @see #setBorderPainted(boolean)
542    */
isBorderPainted()543   public boolean isBorderPainted()
544   {
545     return paintBorder;
546   }
547 
548   /**
549    * Sets the flag that controls whether or not the component's border is
550    * painted.  If the flag value is changed, this method sends a
551    * {@link PropertyChangeEvent} (with the property name "borderPainted") to
552    * all registered listeners.
553    *
554    * @param painted  the new flag value.
555    *
556    * @see #isBorderPainted()
557    * @see #paintBorder
558    */
setBorderPainted(boolean painted)559   public void setBorderPainted(boolean painted)
560   {
561     if (painted != paintBorder)
562       {
563         boolean oldPainted = paintBorder;
564         paintBorder = painted;
565         firePropertyChange("borderPainted", oldPainted, paintBorder);
566       }
567   }
568 
569   /**
570    * Returns the UI delegate for this <code>JProgressBar</code>.
571    *
572    * @return The UI delegate.
573    */
getUI()574   public ProgressBarUI getUI()
575   {
576     return (ProgressBarUI) ui;
577   }
578 
579   /**
580    * Sets the UI delegate for this component.
581    *
582    * @param ui  the new UI delegate.
583    */
setUI(ProgressBarUI ui)584   public void setUI(ProgressBarUI ui)
585   {
586     super.setUI(ui);
587   }
588 
589   /**
590    * Sets this <code>JProgressBar</code>'s UI delegate to the default
591    * (obtained from the {@link UIManager}) for the current look and feel.
592    */
updateUI()593   public void updateUI()
594   {
595     setUI((ProgressBarUI) UIManager.getUI(this));
596   }
597 
598   /**
599    * Returns the suffix (<code>"ProgressBarUI"</code> in this case) used to
600    * determine the class name for a UI delegate that can provide the look and
601    * feel for a <code>JProgressBar</code>.
602    *
603    * @return <code>"ProgressBarUI"</code>.
604    */
getUIClassID()605   public String getUIClassID()
606   {
607     return "ProgressBarUI";
608   }
609 
610   /**
611    * Creates a new {@link ChangeListener} that calls
612    * {@link #fireStateChanged()} whenever it receives a {@link ChangeEvent}
613    * (typically from the component's <code>model</code>).  This listener is
614    * registered with the progress bar's model, so that changes made to the
615    * model directly will automatically result in the progress bar's listeners
616    * being notified also.
617    *
618    * @return A new listener.
619    */
createChangeListener()620   protected ChangeListener createChangeListener()
621   {
622     return new ChangeListener()
623       {
624         public void stateChanged(ChangeEvent ce)
625         {
626           fireStateChanged();
627             }
628       };
629   }
630 
631   /**
632    * Registers a listener with this component so that it will receive
633    * notification of component state changes.
634    *
635    * @param listener  the listener.
636    *
637    * @see #removeChangeListener(ChangeListener)
638    */
639   public void addChangeListener(ChangeListener listener)
640   {
641     listenerList.add(ChangeListener.class, listener);
642   }
643 
644   /**
645    * Deregisters a listener so that it no longer receives notification of
646    * component state changes.
647    *
648    * @param listener  the listener.
649    *
650    * @see #addChangeListener(ChangeListener)
651    */
652   public void removeChangeListener(ChangeListener listener)
653   {
654     listenerList.remove(ChangeListener.class, listener);
655   }
656 
657   /**
658    * Returns an array of the listeners that are registered with this component.
659    * The array may be empty, but is never <code>null</code>.
660    *
661    * @return An array of listeners.
662    *
663    * @since 1.4
664    */
665   public ChangeListener[] getChangeListeners()
666   {
667     return (ChangeListener[]) listenerList.getListeners(ChangeListener.class);
668   }
669 
670   /**
671    * Sends a {@link ChangeEvent} to all registered listeners to indicate that
672    * the state of the <code>JProgressBar</code> has changed.
673    *
674    * @see #createChangeListener()
675    */
676   protected void fireStateChanged()
677   {
678     Object[] changeListeners = listenerList.getListenerList();
679     if (changeEvent == null)
680       changeEvent = new ChangeEvent(this);
681     for (int i = changeListeners.length - 2; i >= 0; i -= 2)
682       {
683         if (changeListeners[i] == ChangeListener.class)
684           ((ChangeListener) changeListeners[i + 1]).stateChanged(changeEvent);
685       }
686   }
687 
688   /**
689    * Returns the model for the <code>JProgressBar</code>.
690    *
691    * @return The model (never <code>null</code>).
692    *
693    * @see #setModel(BoundedRangeModel)
694    */
695   public BoundedRangeModel getModel()
696   {
697     return model;
698   }
699 
700   /**
701    * Sets the model for the <code>JProgressBar</code> and sends a
702    * {@link ChangeEvent} to all registered listeners.
703    *
704    * @param model  the model (<code>null</code> not permitted).
705    *
706    * @see #getModel()
707    */
708   public void setModel(BoundedRangeModel model)
709   {
710     if (model != this.model)
711       {
712         this.model.removeChangeListener(changeListener);
713         this.model = model;
714         this.model.addChangeListener(changeListener);
715         fireStateChanged();
716       }
717   }
718 
719   /**
720    * Returns the minimum value for the <code>JProgressBar</code>. This defines
721    * the lower bound for the current value, and is stored in the component's
722    * <code>model</code>.
723    *
724    * @return The minimum value.
725    *
726    * @see #setMinimum(int)
727    */
728   public int getMinimum()
729   {
730     return model.getMinimum();
731   }
732 
733   /**
734    * Sets the minimum value for the <code>JProgressBar</code>.  The value is
735    * stored in the component's <code>model</code> (see {@link #getModel()}).
736    * If the new value is different to the old value, a {@link ChangeEvent} is
737    * sent to the model's registered listeners.  In turn, this triggers a call
738    * to {@link #fireStateChanged()} which will send a <code>ChangeEvent</code>
739    * to this component's registered listeners.
740    *
741    * @param minimum  the minimum value.
742    *
743    * @see #getMinimum()
744    */
745   public void setMinimum(int minimum)
746   {
747     model.setMinimum(minimum);
748   }
749 
750   /**
751    * Returns the maximum value for the <code>JProgressBar</code>.  This defines
752    * the upper bound for the current value, and is stored in the component's
753    * <code>model</code>.
754    *
755    * @return The maximum value.
756    *
757    * @see #setMaximum(int)
758    */
759   public int getMaximum()
760   {
761     return model.getMaximum();
762   }
763 
764   /**
765    * Sets the maximum value for the <code>JProgressBar</code>.  The value is
766    * stored in the component's <code>model</code> (see {@link #getModel()}).
767    * If the new value is different to the old value, a {@link ChangeEvent} is
768    * sent to the model's registered listeners.  In turn, this triggers a call
769    * to {@link #fireStateChanged()} which will send a <code>ChangeEvent</code>
770    * to this component's registered listeners.
771    *
772    * @param maximum  the maximum value.
773    *
774    * @see #getMaximum()
775    */
776   public void setMaximum(int maximum)
777   {
778     model.setMaximum(maximum);
779   }
780 
781   /**
782    * Returns an implementation-dependent string describing the attributes of
783    * this <code>JProgressBar</code>.
784    *
785    * @return A string describing the attributes of this
786    *     <code>JProgressBar</code> (never <code>null</code>).
787    */
788   protected String paramString()
789   {
790     String superParamStr = super.paramString();
791     CPStringBuilder sb = new CPStringBuilder();
792     sb.append(",orientation=");
793     if (orientation == HORIZONTAL)
794       sb.append("HORIZONTAL");
795     else
796       sb.append("VERTICAL");
797     sb.append(",paintBorder=").append(isBorderPainted());
798     sb.append(",paintString=").append(isStringPainted());
799     sb.append(",progressString=");
800     if (progressString != null)
801       sb.append(progressString);
802     sb.append(",indeterminateString=").append(isIndeterminate());
803     return superParamStr + sb.toString();
804   }
805 
806   /**
807    * Sets the flag that controls the mode for this <code>JProgressBar</code>
808    * (<code>true</code> for indeterminate mode, and <code>false</code> for
809    * determinate mode).  If the flag value changes, this method sends a
810    * {@link PropertyChangeEvent} (with the property name
811    * <code>"indeterminate"</code>) to all registered listeners.
812    * <p>
813    * If the <code>JProgressBar</code> is determinate, it paints a percentage
814    * of the bar described by its value. If it is indeterminate, it simply
815    * bounces a box between the ends of the bar; the value of the
816    * <code>JProgressBar</code> is ignored.
817    *
818    * @param flag  the new flag value.
819    *
820    * @see #isIndeterminate()
821    * @since 1.4
822    */
823   public void setIndeterminate(boolean flag)
824   {
825     if (indeterminate != flag)
826       {
827         indeterminate = flag;
828         firePropertyChange("indeterminate", !flag, indeterminate);
829       }
830   }
831 
832   /**
833    * Returns a flag that indicates the mode for this <code>JProgressBar</code>
834    * (<code>true</code> for indeterminate mode, and <code>false</code> for
835    * determinate mode).
836    *
837    * @return A flag indicating the mode for the <code>JProgressBar</code>.
838    *
839    * @see #setIndeterminate(boolean)
840    * @since 1.4
841    */
842   public boolean isIndeterminate()
843   {
844     return indeterminate;
845   }
846 
847   /**
848    * Returns the object that provides accessibility features for this
849    * <code>JProgressBar</code> component.
850    *
851    * @return The accessible context (an instance of
852    *     {@link AccessibleJProgressBar}).
853    */
854   public AccessibleContext getAccessibleContext()
855   {
856     if (accessibleContext == null)
857       accessibleContext = new AccessibleJProgressBar();
858 
859     return accessibleContext;
860   }
861 }
862