001    /* JProgressBar.java --
002       Copyright (C) 2002, 2004, 2005, 2006  Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    
039    package javax.swing;
040    
041    import gnu.java.lang.CPStringBuilder;
042    
043    import java.awt.Graphics;
044    import java.beans.PropertyChangeEvent;
045    
046    import javax.accessibility.Accessible;
047    import javax.accessibility.AccessibleContext;
048    import javax.accessibility.AccessibleRole;
049    import javax.accessibility.AccessibleState;
050    import javax.accessibility.AccessibleStateSet;
051    import javax.accessibility.AccessibleValue;
052    import javax.swing.border.Border;
053    import javax.swing.event.ChangeEvent;
054    import javax.swing.event.ChangeListener;
055    import javax.swing.plaf.ProgressBarUI;
056    
057    /**
058     * A component that displays a visual indicator of the progress of a task. The
059     * component has two modes: determinate and indeterminate.  In determinate mode,
060     * the <code>JProgressBar</code> fills a percentage of its bar based on its
061     * current value. In indeterminate mode, it creates box and bounces it between
062     * its bounds.
063     * <p>
064     * This component has the following properties:
065     * </p>
066     * <table>
067     * <tr><th> Property         </th><th> Stored in   </th><th> Bound? </th></tr>
068     * <tr><td> borderPainted    </td><td> progressBar </td><td> yes    </td></tr>
069     * <tr><td> changeListeners  </td><td> progressBar </td><td> no     </td></tr>
070     * <tr><td> indeterminate    </td><td> progressBar </td><td> yes    </td></tr>
071     * <tr><td> maximum          </td><td> model       </td><td> no     </td></tr>
072     * <tr><td> minimum          </td><td> model       </td><td> no     </td></tr>
073     * <tr><td> model            </td><td> progressBar </td><td> no     </td></tr>
074     * <tr><td> orientation      </td><td> progressBar </td><td> yes    </td></tr>
075     * <tr><td> percentComplete  </td><td> progressBar </td><td> no     </td></tr>
076     * <tr><td> string           </td><td> progressBar </td><td> yes    </td></tr>
077     * <tr><td> stringPainted    </td><td> progressBar </td><td> yes    </td></tr>
078     * <tr><td> value            </td><td> model       </td><td> no     </td></tr>
079     * </table>
080     */
081    public class JProgressBar extends JComponent implements SwingConstants,
082                                                            Accessible
083    {
084      /**
085       * Provides the accessibility features for the <code>JProgressBar</code>
086       * component.
087       */
088      protected class AccessibleJProgressBar extends AccessibleJComponent
089        implements AccessibleValue
090      {
091        private static final long serialVersionUID = -2938130009392721813L;
092    
093        /**
094         * Creates a new <code>AccessibleJProgressBar</code> instance.
095         */
096        protected AccessibleJProgressBar()
097        {
098          // Nothing to do here.
099        }
100    
101        /**
102         * Returns a set containing the current state of the {@link JProgressBar}
103         * component.
104         *
105         * @return The accessible state set.
106         */
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         */
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         */
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         */
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         */
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         */
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         */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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    }