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