001/* JProgressBar.java --
002   Copyright (C) 2002, 2004, 2005, 2006  Free Software Foundation, Inc.
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038
039package javax.swing;
040
041import gnu.java.lang.CPStringBuilder;
042
043import java.awt.Graphics;
044import java.beans.PropertyChangeEvent;
045
046import javax.accessibility.Accessible;
047import javax.accessibility.AccessibleContext;
048import javax.accessibility.AccessibleRole;
049import javax.accessibility.AccessibleState;
050import javax.accessibility.AccessibleStateSet;
051import javax.accessibility.AccessibleValue;
052import javax.swing.border.Border;
053import javax.swing.event.ChangeEvent;
054import javax.swing.event.ChangeListener;
055import 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 */
081public 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}