1 /*
2  * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package javax.swing;
27 
28 import javax.swing.event.*;
29 import javax.swing.plaf.*;
30 import javax.accessibility.*;
31 
32 import java.io.Serializable;
33 import java.io.ObjectOutputStream;
34 import java.io.IOException;
35 
36 import java.awt.*;
37 import java.util.*;
38 import java.beans.*;
39 
40 
41 /**
42  * A component that lets the user graphically select a value by sliding
43  * a knob within a bounded interval. The knob is always positioned
44  * at the points that match integer values within the specified interval.
45  * <p>
46  * The slider can show both
47  * major tick marks, and minor tick marks between the major ones.  The number of
48  * values between the tick marks is controlled with
49  * <code>setMajorTickSpacing</code> and <code>setMinorTickSpacing</code>.
50  * Painting of tick marks is controlled by {@code setPaintTicks}.
51  * <p>
52  * Sliders can also print text labels at regular intervals (or at
53  * arbitrary locations) along the slider track.  Painting of labels is
54  * controlled by {@code setLabelTable} and {@code setPaintLabels}.
55  * <p>
56  * For further information and examples see
57  * <a
58  href="https://docs.oracle.com/javase/tutorial/uiswing/components/slider.html">How to Use Sliders</a>,
59  * a section in <em>The Java Tutorial.</em>
60  * <p>
61  * <strong>Warning:</strong> Swing is not thread safe. For more
62  * information see <a
63  * href="package-summary.html#threading">Swing's Threading
64  * Policy</a>.
65  * <p>
66  * <strong>Warning:</strong>
67  * Serialized objects of this class will not be compatible with
68  * future Swing releases. The current serialization support is
69  * appropriate for short term storage or RMI between applications running
70  * the same version of Swing.  As of 1.4, support for long term storage
71  * of all JavaBeans&trade;
72  * has been added to the <code>java.beans</code> package.
73  * Please see {@link java.beans.XMLEncoder}.
74  *
75  * @beaninfo
76  *      attribute: isContainer false
77  *    description: A component that supports selecting a integer value from a range.
78  *
79  * @author David Kloba
80  */
81 public class JSlider extends JComponent implements SwingConstants, Accessible {
82     /**
83      * @see #getUIClassID
84      * @see #readObject
85      */
86     private static final String uiClassID = "SliderUI";
87 
88     private boolean paintTicks = false;
89     private boolean paintTrack = true;
90     private boolean paintLabels = false;
91     private boolean isInverted = false;
92 
93     /**
94      * The data model that handles the numeric maximum value,
95      * minimum value, and current-position value for the slider.
96      */
97     protected BoundedRangeModel sliderModel;
98 
99     /**
100      * The number of values between the major tick marks -- the
101      * larger marks that break up the minor tick marks.
102      */
103     protected int majorTickSpacing;
104 
105     /**
106      * The number of values between the minor tick marks -- the
107      * smaller marks that occur between the major tick marks.
108      * @see #setMinorTickSpacing
109      */
110     protected int minorTickSpacing;
111 
112     /**
113      * If true, the knob (and the data value it represents)
114      * resolve to the closest tick mark next to where the user
115      * positioned the knob.  The default is false.
116      * @see #setSnapToTicks
117      */
118     protected boolean snapToTicks = false;
119 
120     /**
121      * If true, the knob (and the data value it represents)
122      * resolve to the closest slider value next to where the user
123      * positioned the knob.
124      */
125     boolean snapToValue = true;
126 
127     /**
128      * Whether the slider is horizontal or vertical
129      * The default is horizontal.
130      *
131      * @see #setOrientation
132      */
133     protected int orientation;
134 
135 
136     /**
137      * {@code Dictionary} of what labels to draw at which values
138      */
139     private Dictionary labelTable;
140 
141 
142     /**
143      * The changeListener (no suffix) is the listener we add to the
144      * slider's model.  This listener is initialized to the
145      * {@code ChangeListener} returned from {@code createChangeListener},
146      * which by default just forwards events
147      * to {@code ChangeListener}s (if any) added directly to the slider.
148      *
149      * @see #addChangeListener
150      * @see #createChangeListener
151      */
152     protected ChangeListener changeListener = createChangeListener();
153 
154 
155     /**
156      * Only one <code>ChangeEvent</code> is needed per slider instance since the
157      * event's only (read-only) state is the source property.  The source
158      * of events generated here is always "this". The event is lazily
159      * created the first time that an event notification is fired.
160      *
161      * @see #fireStateChanged
162      */
163     protected transient ChangeEvent changeEvent = null;
164 
165 
checkOrientation(int orientation)166     private void checkOrientation(int orientation) {
167         switch (orientation) {
168         case VERTICAL:
169         case HORIZONTAL:
170             break;
171         default:
172             throw new IllegalArgumentException("orientation must be one of: VERTICAL, HORIZONTAL");
173         }
174     }
175 
176 
177     /**
178      * Creates a horizontal slider with the range 0 to 100 and
179      * an initial value of 50.
180      */
JSlider()181     public JSlider() {
182         this(HORIZONTAL, 0, 100, 50);
183     }
184 
185 
186     /**
187      * Creates a slider using the specified orientation with the
188      * range {@code 0} to {@code 100} and an initial value of {@code 50}.
189      * The orientation can be
190      * either <code>SwingConstants.VERTICAL</code> or
191      * <code>SwingConstants.HORIZONTAL</code>.
192      *
193      * @param  orientation  the orientation of the slider
194      * @throws IllegalArgumentException if orientation is not one of {@code VERTICAL}, {@code HORIZONTAL}
195      * @see #setOrientation
196      */
JSlider(int orientation)197     public JSlider(int orientation) {
198         this(orientation, 0, 100, 50);
199     }
200 
201 
202     /**
203      * Creates a horizontal slider using the specified min and max
204      * with an initial value equal to the average of the min plus max.
205      * <p>
206      * The <code>BoundedRangeModel</code> that holds the slider's data
207      * handles any issues that may arise from improperly setting the
208      * minimum and maximum values on the slider.  See the
209      * {@code BoundedRangeModel} documentation for details.
210      *
211      * @param min  the minimum value of the slider
212      * @param max  the maximum value of the slider
213      *
214      * @see BoundedRangeModel
215      * @see #setMinimum
216      * @see #setMaximum
217      */
JSlider(int min, int max)218     public JSlider(int min, int max) {
219         this(HORIZONTAL, min, max, (min + max) / 2);
220     }
221 
222 
223     /**
224      * Creates a horizontal slider using the specified min, max and value.
225      * <p>
226      * The <code>BoundedRangeModel</code> that holds the slider's data
227      * handles any issues that may arise from improperly setting the
228      * minimum, initial, and maximum values on the slider.  See the
229      * {@code BoundedRangeModel} documentation for details.
230      *
231      * @param min  the minimum value of the slider
232      * @param max  the maximum value of the slider
233      * @param value  the initial value of the slider
234      *
235      * @see BoundedRangeModel
236      * @see #setMinimum
237      * @see #setMaximum
238      * @see #setValue
239      */
JSlider(int min, int max, int value)240     public JSlider(int min, int max, int value) {
241         this(HORIZONTAL, min, max, value);
242     }
243 
244 
245     /**
246      * Creates a slider with the specified orientation and the
247      * specified minimum, maximum, and initial values.
248      * The orientation can be
249      * either <code>SwingConstants.VERTICAL</code> or
250      * <code>SwingConstants.HORIZONTAL</code>.
251      * <p>
252      * The <code>BoundedRangeModel</code> that holds the slider's data
253      * handles any issues that may arise from improperly setting the
254      * minimum, initial, and maximum values on the slider.  See the
255      * {@code BoundedRangeModel} documentation for details.
256      *
257      * @param orientation  the orientation of the slider
258      * @param min  the minimum value of the slider
259      * @param max  the maximum value of the slider
260      * @param value  the initial value of the slider
261      *
262      * @throws IllegalArgumentException if orientation is not one of {@code VERTICAL}, {@code HORIZONTAL}
263      *
264      * @see BoundedRangeModel
265      * @see #setOrientation
266      * @see #setMinimum
267      * @see #setMaximum
268      * @see #setValue
269      */
JSlider(int orientation, int min, int max, int value)270     public JSlider(int orientation, int min, int max, int value)
271     {
272         checkOrientation(orientation);
273         this.orientation = orientation;
274         setModel(new DefaultBoundedRangeModel(value, 0, min, max));
275         updateUI();
276     }
277 
278 
279     /**
280      * Creates a horizontal slider using the specified
281      * BoundedRangeModel.
282      */
JSlider(BoundedRangeModel brm)283     public JSlider(BoundedRangeModel brm)
284     {
285         this.orientation = JSlider.HORIZONTAL;
286         setModel(brm);
287         updateUI();
288     }
289 
290 
291     /**
292      * Gets the UI object which implements the L&amp;F for this component.
293      *
294      * @return the SliderUI object that implements the Slider L&amp;F
295      */
getUI()296     public SliderUI getUI() {
297         return(SliderUI)ui;
298     }
299 
300 
301     /**
302      * Sets the UI object which implements the L&amp;F for this component.
303      *
304      * @param ui the SliderUI L&amp;F object
305      * @see UIDefaults#getUI
306      * @beaninfo
307      *        bound: true
308      *       hidden: true
309      *    attribute: visualUpdate true
310      *  description: The UI object that implements the slider's LookAndFeel.
311      */
setUI(SliderUI ui)312     public void setUI(SliderUI ui) {
313         super.setUI(ui);
314     }
315 
316 
317     /**
318      * Resets the UI property to a value from the current look and feel.
319      *
320      * @see JComponent#updateUI
321      */
updateUI()322     public void updateUI() {
323         setUI((SliderUI)UIManager.getUI(this));
324         // The labels preferred size may be derived from the font
325         // of the slider, so we must update the UI of the slider first, then
326         // that of labels.  This way when setSize is called the right
327         // font is used.
328         updateLabelUIs();
329     }
330 
331 
332     /**
333      * Returns the name of the L&amp;F class that renders this component.
334      *
335      * @return "SliderUI"
336      * @see JComponent#getUIClassID
337      * @see UIDefaults#getUI
338      */
getUIClassID()339     public String getUIClassID() {
340         return uiClassID;
341     }
342 
343 
344     /**
345      * We pass Change events along to the listeners with the
346      * the slider (instead of the model itself) as the event source.
347      */
348     private class ModelListener implements ChangeListener, Serializable {
stateChanged(ChangeEvent e)349         public void stateChanged(ChangeEvent e) {
350             fireStateChanged();
351         }
352     }
353 
354 
355     /**
356      * Subclasses that want to handle {@code ChangeEvent}s
357      * from the model differently
358      * can override this to return
359      * an instance of a custom <code>ChangeListener</code> implementation.
360      * The default {@code ChangeListener} simply calls the
361      * {@code fireStateChanged} method to forward {@code ChangeEvent}s
362      * to the {@code ChangeListener}s that have been added directly to the
363      * slider.
364      * @see #changeListener
365      * @see #fireStateChanged
366      * @see javax.swing.event.ChangeListener
367      * @see javax.swing.BoundedRangeModel
368      */
createChangeListener()369     protected ChangeListener createChangeListener() {
370         return new ModelListener();
371     }
372 
373 
374     /**
375      * Adds a ChangeListener to the slider.
376      *
377      * @param l the ChangeListener to add
378      * @see #fireStateChanged
379      * @see #removeChangeListener
380      */
addChangeListener(ChangeListener l)381     public void addChangeListener(ChangeListener l) {
382         listenerList.add(ChangeListener.class, l);
383     }
384 
385 
386     /**
387      * Removes a ChangeListener from the slider.
388      *
389      * @param l the ChangeListener to remove
390      * @see #fireStateChanged
391      * @see #addChangeListener
392 
393      */
removeChangeListener(ChangeListener l)394     public void removeChangeListener(ChangeListener l) {
395         listenerList.remove(ChangeListener.class, l);
396     }
397 
398 
399     /**
400      * Returns an array of all the <code>ChangeListener</code>s added
401      * to this JSlider with addChangeListener().
402      *
403      * @return all of the <code>ChangeListener</code>s added or an empty
404      *         array if no listeners have been added
405      * @since 1.4
406      */
getChangeListeners()407     public ChangeListener[] getChangeListeners() {
408         return listenerList.getListeners(ChangeListener.class);
409     }
410 
411 
412     /**
413      * Send a {@code ChangeEvent}, whose source is this {@code JSlider}, to
414      * all {@code ChangeListener}s that have registered interest in
415      * {@code ChangeEvent}s.
416      * This method is called each time a {@code ChangeEvent} is received from
417      * the model.
418      * <p>
419      * The event instance is created if necessary, and stored in
420      * {@code changeEvent}.
421      *
422      * @see #addChangeListener
423      * @see EventListenerList
424      */
fireStateChanged()425     protected void fireStateChanged() {
426         Object[] listeners = listenerList.getListenerList();
427         for (int i = listeners.length - 2; i >= 0; i -= 2) {
428             if (listeners[i]==ChangeListener.class) {
429                 if (changeEvent == null) {
430                     changeEvent = new ChangeEvent(this);
431                 }
432                 ((ChangeListener)listeners[i+1]).stateChanged(changeEvent);
433             }
434         }
435     }
436 
437 
438     /**
439      * Returns the {@code BoundedRangeModel} that handles the slider's three
440      * fundamental properties: minimum, maximum, value.
441      *
442      * @return the data model for this component
443      * @see #setModel
444      * @see    BoundedRangeModel
445      */
getModel()446     public BoundedRangeModel getModel() {
447         return sliderModel;
448     }
449 
450 
451     /**
452      * Sets the {@code BoundedRangeModel} that handles the slider's three
453      * fundamental properties: minimum, maximum, value.
454      *<p>
455      * Attempts to pass a {@code null} model to this method result in
456      * undefined behavior, and, most likely, exceptions.
457      *
458      * @param  newModel the new, {@code non-null} <code>BoundedRangeModel</code> to use
459      *
460      * @see #getModel
461      * @see    BoundedRangeModel
462      * @beaninfo
463      *       bound: true
464      * description: The sliders BoundedRangeModel.
465      */
setModel(BoundedRangeModel newModel)466     public void setModel(BoundedRangeModel newModel)
467     {
468         BoundedRangeModel oldModel = getModel();
469 
470         if (oldModel != null) {
471             oldModel.removeChangeListener(changeListener);
472         }
473 
474         sliderModel = newModel;
475 
476         if (newModel != null) {
477             newModel.addChangeListener(changeListener);
478         }
479 
480         if (accessibleContext != null) {
481             accessibleContext.firePropertyChange(
482                                                 AccessibleContext.ACCESSIBLE_VALUE_PROPERTY,
483                                                 (oldModel == null
484                                                  ? null : Integer.valueOf(oldModel.getValue())),
485                                                 (newModel == null
486                                                  ? null : Integer.valueOf(newModel.getValue())));
487         }
488 
489         firePropertyChange("model", oldModel, sliderModel);
490     }
491 
492 
493     /**
494      * Returns the slider's current value
495      * from the {@code BoundedRangeModel}.
496      *
497      * @return  the current value of the slider
498      * @see     #setValue
499      * @see     BoundedRangeModel#getValue
500      */
getValue()501     public int getValue() {
502         return getModel().getValue();
503     }
504 
505     /**
506      * Sets the slider's current value to {@code n}.  This method
507      * forwards the new value to the model.
508      * <p>
509      * The data model (an instance of {@code BoundedRangeModel})
510      * handles any mathematical
511      * issues arising from assigning faulty values.  See the
512      * {@code BoundedRangeModel} documentation for details.
513      * <p>
514      * If the new value is different from the previous value,
515      * all change listeners are notified.
516      *
517      * @param   n       the new value
518      * @see     #getValue
519      * @see     #addChangeListener
520      * @see     BoundedRangeModel#setValue
521      * @beaninfo
522      *   preferred: true
523      * description: The sliders current value.
524      */
setValue(int n)525     public void setValue(int n) {
526         BoundedRangeModel m = getModel();
527         int oldValue = m.getValue();
528         if (oldValue == n) {
529             return;
530         }
531         m.setValue(n);
532 
533         if (accessibleContext != null) {
534             accessibleContext.firePropertyChange(
535                                                 AccessibleContext.ACCESSIBLE_VALUE_PROPERTY,
536                                                 Integer.valueOf(oldValue),
537                                                 Integer.valueOf(m.getValue()));
538         }
539     }
540 
541 
542     /**
543      * Returns the minimum value supported by the slider
544      * from the <code>BoundedRangeModel</code>.
545      *
546      * @return the value of the model's minimum property
547      * @see #setMinimum
548      * @see     BoundedRangeModel#getMinimum
549      */
getMinimum()550     public int getMinimum() {
551         return getModel().getMinimum();
552     }
553 
554 
555     /**
556      * Sets the slider's minimum value to {@code minimum}.  This method
557      * forwards the new minimum value to the model.
558      * <p>
559      * The data model (an instance of {@code BoundedRangeModel})
560      * handles any mathematical
561      * issues arising from assigning faulty values.  See the
562      * {@code BoundedRangeModel} documentation for details.
563      * <p>
564      * If the new minimum value is different from the previous minimum value,
565      * all change listeners are notified.
566      *
567      * @param minimum  the new minimum
568      * @see #getMinimum
569      * @see    #addChangeListener
570      * @see BoundedRangeModel#setMinimum
571      * @beaninfo
572      *       bound: true
573      *   preferred: true
574      * description: The sliders minimum value.
575      */
setMinimum(int minimum)576     public void setMinimum(int minimum) {
577         int oldMin = getModel().getMinimum();
578         getModel().setMinimum(minimum);
579         firePropertyChange( "minimum", Integer.valueOf( oldMin ), Integer.valueOf( minimum ) );
580     }
581 
582 
583     /**
584      * Returns the maximum value supported by the slider
585      * from the <code>BoundedRangeModel</code>.
586      *
587      * @return the value of the model's maximum property
588      * @see #setMaximum
589      * @see BoundedRangeModel#getMaximum
590      */
getMaximum()591     public int getMaximum() {
592         return getModel().getMaximum();
593     }
594 
595 
596     /**
597      * Sets the slider's maximum value to {@code maximum}.  This method
598      * forwards the new maximum value to the model.
599      * <p>
600      * The data model (an instance of {@code BoundedRangeModel})
601      * handles any mathematical
602      * issues arising from assigning faulty values.  See the
603      * {@code BoundedRangeModel} documentation for details.
604      * <p>
605      * If the new maximum value is different from the previous maximum value,
606      * all change listeners are notified.
607      *
608      * @param maximum  the new maximum
609      * @see #getMaximum
610      * @see #addChangeListener
611      * @see BoundedRangeModel#setMaximum
612      * @beaninfo
613      *       bound: true
614      *   preferred: true
615      * description: The sliders maximum value.
616      */
setMaximum(int maximum)617     public void setMaximum(int maximum) {
618         int oldMax = getModel().getMaximum();
619         getModel().setMaximum(maximum);
620         firePropertyChange( "maximum", Integer.valueOf( oldMax ), Integer.valueOf( maximum ) );
621     }
622 
623 
624     /**
625      * Returns the {@code valueIsAdjusting} property from the model.  For
626      * details on how this is used, see the {@code setValueIsAdjusting}
627      * documentation.
628      *
629      * @return the value of the model's {@code valueIsAdjusting} property
630      * @see #setValueIsAdjusting
631      */
getValueIsAdjusting()632     public boolean getValueIsAdjusting() {
633         return getModel().getValueIsAdjusting();
634     }
635 
636 
637     /**
638      * Sets the model's {@code valueIsAdjusting} property.  Slider look and
639      * feel implementations should set this property to {@code true} when
640      * a knob drag begins, and to {@code false} when the drag ends.
641      *
642      * @param b the new value for the {@code valueIsAdjusting} property
643      * @see   #getValueIsAdjusting
644      * @see   BoundedRangeModel#setValueIsAdjusting
645      * @beaninfo
646      *      expert: true
647      * description: True if the slider knob is being dragged.
648      */
setValueIsAdjusting(boolean b)649     public void setValueIsAdjusting(boolean b) {
650         BoundedRangeModel m = getModel();
651         boolean oldValue = m.getValueIsAdjusting();
652         m.setValueIsAdjusting(b);
653 
654         if ((oldValue != b) && (accessibleContext != null)) {
655             accessibleContext.firePropertyChange(
656                                                 AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
657                                                 ((oldValue) ? AccessibleState.BUSY : null),
658                                                 ((b) ? AccessibleState.BUSY : null));
659         }
660     }
661 
662 
663     /**
664      * Returns the "extent" from the <code>BoundedRangeModel</code>.
665      * This represents the range of values "covered" by the knob.
666      *
667      * @return an int representing the extent
668      * @see #setExtent
669      * @see BoundedRangeModel#getExtent
670      */
getExtent()671     public int getExtent() {
672         return getModel().getExtent();
673     }
674 
675 
676     /**
677      * Sets the size of the range "covered" by the knob.  Most look
678      * and feel implementations will change the value by this amount
679      * if the user clicks on either side of the knob.  This method just
680      * forwards the new extent value to the model.
681      * <p>
682      * The data model (an instance of {@code BoundedRangeModel})
683      * handles any mathematical
684      * issues arising from assigning faulty values.  See the
685      * {@code BoundedRangeModel} documentation for details.
686      * <p>
687      * If the new extent value is different from the previous extent value,
688      * all change listeners are notified.
689      *
690      * @param extent the new extent
691      * @see   #getExtent
692      * @see   BoundedRangeModel#setExtent
693      * @beaninfo
694      *      expert: true
695      * description: Size of the range covered by the knob.
696      */
setExtent(int extent)697     public void setExtent(int extent) {
698         getModel().setExtent(extent);
699     }
700 
701 
702     /**
703      * Return this slider's vertical or horizontal orientation.
704      * @return {@code SwingConstants.VERTICAL} or
705      *  {@code SwingConstants.HORIZONTAL}
706      * @see #setOrientation
707      */
getOrientation()708     public int getOrientation() {
709         return orientation;
710     }
711 
712 
713     /**
714      * Set the slider's orientation to either {@code SwingConstants.VERTICAL} or
715      * {@code SwingConstants.HORIZONTAL}.
716      *
717      * @param orientation {@code HORIZONTAL} or {@code VERTICAL}
718      * @throws IllegalArgumentException if orientation is not one of {@code VERTICAL}, {@code HORIZONTAL}
719      * @see #getOrientation
720      * @beaninfo
721      *    preferred: true
722      *        bound: true
723      *    attribute: visualUpdate true
724      *  description: Set the scrollbars orientation to either VERTICAL or HORIZONTAL.
725      *         enum: VERTICAL JSlider.VERTICAL
726      *               HORIZONTAL JSlider.HORIZONTAL
727      *
728      */
setOrientation(int orientation)729     public void setOrientation(int orientation)
730     {
731         checkOrientation(orientation);
732         int oldValue = this.orientation;
733         this.orientation = orientation;
734         firePropertyChange("orientation", oldValue, orientation);
735 
736         if ((oldValue != orientation) && (accessibleContext != null)) {
737             accessibleContext.firePropertyChange(
738                                                 AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
739                                                 ((oldValue == VERTICAL)
740                                                  ? AccessibleState.VERTICAL : AccessibleState.HORIZONTAL),
741                                                 ((orientation == VERTICAL)
742                                                  ? AccessibleState.VERTICAL : AccessibleState.HORIZONTAL));
743         }
744         if (orientation != oldValue) {
745             revalidate();
746         }
747     }
748 
749 
750     /**
751      * {@inheritDoc}
752      *
753      * @since 1.6
754      */
setFont(Font font)755     public void setFont(Font font) {
756         super.setFont(font);
757         updateLabelSizes();
758     }
759 
760     /**
761      * {@inheritDoc}
762      * @since 1.7
763      */
imageUpdate(Image img, int infoflags, int x, int y, int w, int h)764     public boolean imageUpdate(Image img, int infoflags, int x, int y, int w, int h) {
765         if (!isShowing()) {
766             return false;
767         }
768 
769         // Check that there is a label with such image
770         Enumeration elements = labelTable.elements();
771 
772         while (elements.hasMoreElements()) {
773             Component component = (Component) elements.nextElement();
774 
775             if (component instanceof JLabel) {
776                 JLabel label = (JLabel) component;
777 
778                 if (SwingUtilities.doesIconReferenceImage(label.getIcon(), img) ||
779                         SwingUtilities.doesIconReferenceImage(label.getDisabledIcon(), img)) {
780                     return super.imageUpdate(img, infoflags, x, y, w, h);
781                 }
782             }
783         }
784 
785         return false;
786     }
787 
788     /**
789      * Returns the dictionary of what labels to draw at which values.
790      *
791      * @return the <code>Dictionary</code> containing labels and
792      *    where to draw them
793      */
getLabelTable()794     public Dictionary getLabelTable() {
795 /*
796         if ( labelTable == null && getMajorTickSpacing() > 0 ) {
797             setLabelTable( createStandardLabels( getMajorTickSpacing() ) );
798         }
799 */
800         return labelTable;
801     }
802 
803 
804     /**
805      * Used to specify what label will be drawn at any given value.
806      * The key-value pairs are of this format:
807      * <code>{ Integer value, java.swing.JComponent label }</code>.
808      * <p>
809      * An easy way to generate a standard table of value labels is by using the
810      * {@code createStandardLabels} method.
811      * <p>
812      * Once the labels have been set, this method calls {@link #updateLabelUIs}.
813      * Note that the labels are only painted if the {@code paintLabels}
814      * property is {@code true}.
815      *
816      * @param labels new {@code Dictionary} of labels, or {@code null} to
817      *        remove all labels
818      * @see #createStandardLabels(int)
819      * @see #getLabelTable
820      * @see #setPaintLabels
821      * @beaninfo
822      *       hidden: true
823      *        bound: true
824      *    attribute: visualUpdate true
825      *  description: Specifies what labels will be drawn for any given value.
826      */
setLabelTable( Dictionary labels )827     public void setLabelTable( Dictionary labels ) {
828         Dictionary oldTable = labelTable;
829         labelTable = labels;
830         updateLabelUIs();
831         firePropertyChange("labelTable", oldTable, labelTable );
832         if (labels != oldTable) {
833             revalidate();
834             repaint();
835         }
836     }
837 
838 
839     /**
840      * Updates the UIs for the labels in the label table by calling
841      * {@code updateUI} on each label.  The UIs are updated from
842      * the current look and feel.  The labels are also set to their
843      * preferred size.
844      *
845      * @see #setLabelTable
846      * @see JComponent#updateUI
847      */
updateLabelUIs()848     protected void updateLabelUIs() {
849         Dictionary labelTable = getLabelTable();
850 
851         if (labelTable == null) {
852             return;
853         }
854         Enumeration labels = labelTable.keys();
855         while ( labels.hasMoreElements() ) {
856             JComponent component = (JComponent) labelTable.get(labels.nextElement());
857             component.updateUI();
858             component.setSize(component.getPreferredSize());
859         }
860     }
861 
updateLabelSizes()862     private void updateLabelSizes() {
863         Dictionary labelTable = getLabelTable();
864         if (labelTable != null) {
865             Enumeration labels = labelTable.elements();
866             while (labels.hasMoreElements()) {
867                 JComponent component = (JComponent) labels.nextElement();
868                 component.setSize(component.getPreferredSize());
869             }
870         }
871     }
872 
873 
874     /**
875      * Creates a {@code Hashtable} of numerical text labels, starting at the
876      * slider minimum, and using the increment specified.
877      * For example, if you call <code>createStandardLabels( 10 )</code>
878      * and the slider minimum is zero,
879      * then labels will be created for the values 0, 10, 20, 30, and so on.
880      * <p>
881      * For the labels to be drawn on the slider, the returned {@code Hashtable}
882      * must be passed into {@code setLabelTable}, and {@code setPaintLabels}
883      * must be set to {@code true}.
884      * <p>
885      * For further details on the makeup of the returned {@code Hashtable}, see
886      * the {@code setLabelTable} documentation.
887      *
888      * @param  increment  distance between labels in the generated hashtable
889      * @return a new {@code Hashtable} of labels
890      * @see #setLabelTable
891      * @see #setPaintLabels
892      * @throws IllegalArgumentException if {@code increment} is less than or
893      *          equal to zero
894      */
createStandardLabels( int increment )895     public Hashtable createStandardLabels( int increment ) {
896         return createStandardLabels( increment, getMinimum() );
897     }
898 
899 
900     /**
901      * Creates a {@code Hashtable} of numerical text labels, starting at the
902      * starting point specified, and using the increment specified.
903      * For example, if you call
904      * <code>createStandardLabels( 10, 2 )</code>,
905      * then labels will be created for the values 2, 12, 22, 32, and so on.
906      * <p>
907      * For the labels to be drawn on the slider, the returned {@code Hashtable}
908      * must be passed into {@code setLabelTable}, and {@code setPaintLabels}
909      * must be set to {@code true}.
910      * <p>
911      * For further details on the makeup of the returned {@code Hashtable}, see
912      * the {@code setLabelTable} documentation.
913      *
914      * @param  increment  distance between labels in the generated hashtable
915      * @param  start      value at which the labels will begin
916      * @return a new {@code Hashtable} of labels
917      * @see #setLabelTable
918      * @see #setPaintLabels
919      * @exception IllegalArgumentException if {@code start} is
920      *          out of range, or if {@code increment} is less than or equal
921      *          to zero
922      */
createStandardLabels( int increment, int start )923     public Hashtable createStandardLabels( int increment, int start ) {
924         if ( start > getMaximum() || start < getMinimum() ) {
925             throw new IllegalArgumentException( "Slider label start point out of range." );
926         }
927 
928         if ( increment <= 0 ) {
929             throw new IllegalArgumentException( "Label incremement must be > 0" );
930         }
931 
932         class SmartHashtable extends Hashtable<Object, Object> implements PropertyChangeListener {
933             int increment = 0;
934             int start = 0;
935             boolean startAtMin = false;
936 
937             class LabelUIResource extends JLabel implements UIResource {
938                 public LabelUIResource( String text, int alignment ) {
939                     super( text, alignment );
940                     setName("Slider.label");
941                 }
942 
943                 public Font getFont() {
944                     Font font = super.getFont();
945                     if (font != null && !(font instanceof UIResource)) {
946                         return font;
947                     }
948                     return JSlider.this.getFont();
949                 }
950 
951                 public Color getForeground() {
952                     Color fg = super.getForeground();
953                     if (fg != null && !(fg instanceof UIResource)) {
954                         return fg;
955                     }
956                     if (!(JSlider.this.getForeground() instanceof UIResource)) {
957                         return JSlider.this.getForeground();
958                     }
959                     return fg;
960                 }
961             }
962 
963             public SmartHashtable( int increment, int start ) {
964                 super();
965                 this.increment = increment;
966                 this.start = start;
967                 startAtMin = start == getMinimum();
968                 createLabels();
969             }
970 
971             public void propertyChange( PropertyChangeEvent e ) {
972                 if ( e.getPropertyName().equals( "minimum" ) && startAtMin ) {
973                     start = getMinimum();
974                 }
975 
976                 if ( e.getPropertyName().equals( "minimum" ) ||
977                      e.getPropertyName().equals( "maximum" ) ) {
978 
979                     Enumeration keys = getLabelTable().keys();
980                     Hashtable<Object, Object> hashtable = new Hashtable<Object, Object>();
981 
982                     // Save the labels that were added by the developer
983                     while ( keys.hasMoreElements() ) {
984                         Object key = keys.nextElement();
985                         Object value = labelTable.get(key);
986                         if ( !(value instanceof LabelUIResource) ) {
987                             hashtable.put( key, value );
988                         }
989                     }
990 
991                     clear();
992                     createLabels();
993 
994                     // Add the saved labels
995                     keys = hashtable.keys();
996                     while ( keys.hasMoreElements() ) {
997                         Object key = keys.nextElement();
998                         put( key, hashtable.get( key ) );
999                     }
1000 
1001                     ((JSlider)e.getSource()).setLabelTable( this );
1002                 }
1003             }
1004 
1005             void createLabels() {
1006                 for ( int labelIndex = start; labelIndex <= getMaximum(); labelIndex += increment ) {
1007                     put( Integer.valueOf( labelIndex ), new LabelUIResource( ""+labelIndex, JLabel.CENTER ) );
1008                 }
1009             }
1010         }
1011 
1012         SmartHashtable table = new SmartHashtable( increment, start );
1013 
1014         Dictionary labelTable = getLabelTable();
1015 
1016         if (labelTable != null && (labelTable instanceof PropertyChangeListener)) {
1017             removePropertyChangeListener((PropertyChangeListener) labelTable);
1018         }
1019 
1020         addPropertyChangeListener( table );
1021 
1022         return table;
1023     }
1024 
1025 
1026     /**
1027      * Returns true if the value-range shown for the slider is reversed,
1028      *
1029      * @return true if the slider values are reversed from their normal order
1030      * @see #setInverted
1031      */
getInverted()1032     public boolean getInverted() {
1033         return isInverted;
1034     }
1035 
1036 
1037     /**
1038      * Specify true to reverse the value-range shown for the slider and false to
1039      * put the value range in the normal order.  The order depends on the
1040      * slider's <code>ComponentOrientation</code> property.  Normal (non-inverted)
1041      * horizontal sliders with a <code>ComponentOrientation</code> value of
1042      * <code>LEFT_TO_RIGHT</code> have their maximum on the right.
1043      * Normal horizontal sliders with a <code>ComponentOrientation</code> value of
1044      * <code>RIGHT_TO_LEFT</code> have their maximum on the left.  Normal vertical
1045      * sliders have their maximum on the top.  These labels are reversed when the
1046      * slider is inverted.
1047      * <p>
1048      * By default, the value of this property is {@code false}.
1049      *
1050      * @param b  true to reverse the slider values from their normal order
1051      * @beaninfo
1052      *        bound: true
1053      *    attribute: visualUpdate true
1054      *  description: If true reverses the slider values from their normal order
1055      *
1056      */
setInverted( boolean b )1057     public void setInverted( boolean b ) {
1058         boolean oldValue = isInverted;
1059         isInverted = b;
1060         firePropertyChange("inverted", oldValue, isInverted);
1061         if (b != oldValue) {
1062             repaint();
1063         }
1064     }
1065 
1066 
1067     /**
1068      * This method returns the major tick spacing.  The number that is returned
1069      * represents the distance, measured in values, between each major tick mark.
1070      * If you have a slider with a range from 0 to 50 and the major tick spacing
1071      * is set to 10, you will get major ticks next to the following values:
1072      * 0, 10, 20, 30, 40, 50.
1073      *
1074      * @return the number of values between major ticks
1075      * @see #setMajorTickSpacing
1076      */
getMajorTickSpacing()1077     public int getMajorTickSpacing() {
1078         return majorTickSpacing;
1079     }
1080 
1081 
1082     /**
1083      * This method sets the major tick spacing.  The number that is passed in
1084      * represents the distance, measured in values, between each major tick mark.
1085      * If you have a slider with a range from 0 to 50 and the major tick spacing
1086      * is set to 10, you will get major ticks next to the following values:
1087      * 0, 10, 20, 30, 40, 50.
1088      * <p>
1089      * In order for major ticks to be painted, {@code setPaintTicks} must be
1090      * set to {@code true}.
1091      * <p>
1092      * This method will also set up a label table for you.
1093      * If there is not already a label table, and the major tick spacing is
1094      * {@code > 0}, and {@code getPaintLabels} returns
1095      * {@code true}, a standard label table will be generated (by calling
1096      * {@code createStandardLabels}) with labels at the major tick marks.
1097      * For the example above, you would get text labels: "0",
1098      * "10", "20", "30", "40", "50".
1099      * The label table is then set on the slider by calling
1100      * {@code setLabelTable}.
1101      *
1102      * @param  n  new value for the {@code majorTickSpacing} property
1103      * @see #getMajorTickSpacing
1104      * @see #setPaintTicks
1105      * @see #setLabelTable
1106      * @see #createStandardLabels(int)
1107      * @beaninfo
1108      *        bound: true
1109      *    attribute: visualUpdate true
1110      *  description: Sets the number of values between major tick marks.
1111      *
1112      */
setMajorTickSpacing(int n)1113     public void setMajorTickSpacing(int n) {
1114         int oldValue = majorTickSpacing;
1115         majorTickSpacing = n;
1116         if ( labelTable == null && getMajorTickSpacing() > 0 && getPaintLabels() ) {
1117             setLabelTable( createStandardLabels( getMajorTickSpacing() ) );
1118         }
1119         firePropertyChange("majorTickSpacing", oldValue, majorTickSpacing);
1120         if (majorTickSpacing != oldValue && getPaintTicks()) {
1121             repaint();
1122         }
1123     }
1124 
1125 
1126 
1127     /**
1128      * This method returns the minor tick spacing.  The number that is returned
1129      * represents the distance, measured in values, between each minor tick mark.
1130      * If you have a slider with a range from 0 to 50 and the minor tick spacing
1131      * is set to 10, you will get minor ticks next to the following values:
1132      * 0, 10, 20, 30, 40, 50.
1133      *
1134      * @return the number of values between minor ticks
1135      * @see #getMinorTickSpacing
1136      */
getMinorTickSpacing()1137     public int getMinorTickSpacing() {
1138         return minorTickSpacing;
1139     }
1140 
1141 
1142     /**
1143      * This method sets the minor tick spacing.  The number that is passed in
1144      * represents the distance, measured in values, between each minor tick mark.
1145      * If you have a slider with a range from 0 to 50 and the minor tick spacing
1146      * is set to 10, you will get minor ticks next to the following values:
1147      * 0, 10, 20, 30, 40, 50.
1148      * <p>
1149      * In order for minor ticks to be painted, {@code setPaintTicks} must be
1150      * set to {@code true}.
1151      *
1152      * @param  n  new value for the {@code minorTickSpacing} property
1153      * @see #getMinorTickSpacing
1154      * @see #setPaintTicks
1155      * @beaninfo
1156      *        bound: true
1157      *    attribute: visualUpdate true
1158      *  description: Sets the number of values between minor tick marks.
1159      */
setMinorTickSpacing(int n)1160     public void setMinorTickSpacing(int n) {
1161         int oldValue = minorTickSpacing;
1162         minorTickSpacing = n;
1163         firePropertyChange("minorTickSpacing", oldValue, minorTickSpacing);
1164         if (minorTickSpacing != oldValue && getPaintTicks()) {
1165             repaint();
1166         }
1167     }
1168 
1169 
1170     /**
1171      * Returns true if the knob (and the data value it represents)
1172      * resolve to the closest tick mark next to where the user
1173      * positioned the knob.
1174      *
1175      * @return true if the value snaps to the nearest tick mark, else false
1176      * @see #setSnapToTicks
1177      */
getSnapToTicks()1178     public boolean getSnapToTicks() {
1179         return snapToTicks;
1180     }
1181 
1182 
1183     /**
1184      * Returns true if the knob (and the data value it represents)
1185      * resolve to the closest slider value next to where the user
1186      * positioned the knob.
1187      *
1188      * @return true if the value snaps to the nearest slider value, else false
1189      * @see #setSnapToValue
1190      */
getSnapToValue()1191     boolean getSnapToValue() {
1192         return snapToValue;
1193     }
1194 
1195 
1196     /**
1197      * Specifying true makes the knob (and the data value it represents)
1198      * resolve to the closest tick mark next to where the user
1199      * positioned the knob.
1200      * By default, this property is {@code false}.
1201      *
1202      * @param b  true to snap the knob to the nearest tick mark
1203      * @see #getSnapToTicks
1204      * @beaninfo
1205      *       bound: true
1206      * description: If true snap the knob to the nearest tick mark.
1207      */
setSnapToTicks(boolean b)1208     public void setSnapToTicks(boolean b) {
1209         boolean oldValue = snapToTicks;
1210         snapToTicks = b;
1211         firePropertyChange("snapToTicks", oldValue, snapToTicks);
1212     }
1213 
1214 
1215     /**
1216      * Specifying true makes the knob (and the data value it represents)
1217      * resolve to the closest slider value next to where the user
1218      * positioned the knob. If the {@code snapToTicks} property has also been
1219      * set to {@code true}, the snap-to-ticks behavior will prevail.
1220      * By default, the snapToValue property is {@code true}.
1221      *
1222      * @param b  true to snap the knob to the nearest slider value
1223      * @see #getSnapToValue
1224      * @see #setSnapToTicks
1225      * @beaninfo
1226      *       bound: true
1227      * description: If true snap the knob to the nearest slider value.
1228      */
setSnapToValue(boolean b)1229     void setSnapToValue(boolean b) {
1230         boolean oldValue = snapToValue;
1231         snapToValue = b;
1232         firePropertyChange("snapToValue", oldValue, snapToValue);
1233     }
1234 
1235 
1236     /**
1237      * Tells if tick marks are to be painted.
1238      * @return true if tick marks are painted, else false
1239      * @see #setPaintTicks
1240      */
getPaintTicks()1241     public boolean getPaintTicks() {
1242         return paintTicks;
1243     }
1244 
1245 
1246     /**
1247      * Determines whether tick marks are painted on the slider.
1248      * By default, this property is {@code false}.
1249      *
1250      * @param  b  whether or not tick marks should be painted
1251      * @see #getPaintTicks
1252      * @beaninfo
1253      *        bound: true
1254      *    attribute: visualUpdate true
1255      *  description: If true tick marks are painted on the slider.
1256      */
setPaintTicks(boolean b)1257     public void setPaintTicks(boolean b) {
1258         boolean oldValue = paintTicks;
1259         paintTicks = b;
1260         firePropertyChange("paintTicks", oldValue, paintTicks);
1261         if (paintTicks != oldValue) {
1262             revalidate();
1263             repaint();
1264         }
1265     }
1266 
1267     /**
1268      * Tells if the track (area the slider slides in) is to be painted.
1269      * @return true if track is painted, else false
1270      * @see #setPaintTrack
1271      */
getPaintTrack()1272     public boolean getPaintTrack() {
1273         return paintTrack;
1274     }
1275 
1276 
1277     /**
1278      * Determines whether the track is painted on the slider.
1279      * By default, this property is {@code true}.
1280      *
1281      * @param  b  whether or not to paint the slider track
1282      * @see #getPaintTrack
1283      * @beaninfo
1284      *        bound: true
1285      *    attribute: visualUpdate true
1286      *  description: If true, the track is painted on the slider.
1287      */
setPaintTrack(boolean b)1288     public void setPaintTrack(boolean b) {
1289         boolean oldValue = paintTrack;
1290         paintTrack = b;
1291         firePropertyChange("paintTrack", oldValue, paintTrack);
1292         if (paintTrack != oldValue) {
1293             repaint();
1294         }
1295     }
1296 
1297 
1298     /**
1299      * Tells if labels are to be painted.
1300      * @return true if labels are painted, else false
1301      * @see #setPaintLabels
1302      */
getPaintLabels()1303     public boolean getPaintLabels() {
1304         return paintLabels;
1305     }
1306 
1307 
1308     /**
1309      * Determines whether labels are painted on the slider.
1310      * <p>
1311      * This method will also set up a label table for you.
1312      * If there is not already a label table, and the major tick spacing is
1313      * {@code > 0},
1314      * a standard label table will be generated (by calling
1315      * {@code createStandardLabels}) with labels at the major tick marks.
1316      * The label table is then set on the slider by calling
1317      * {@code setLabelTable}.
1318      * <p>
1319      * By default, this property is {@code false}.
1320      *
1321      * @param  b  whether or not to paint labels
1322      * @see #getPaintLabels
1323      * @see #getLabelTable
1324      * @see #createStandardLabels(int)
1325      * @beaninfo
1326      *        bound: true
1327      *    attribute: visualUpdate true
1328      *  description: If true labels are painted on the slider.
1329      */
setPaintLabels(boolean b)1330     public void setPaintLabels(boolean b) {
1331         boolean oldValue = paintLabels;
1332         paintLabels = b;
1333         if ( labelTable == null && getMajorTickSpacing() > 0 ) {
1334             setLabelTable( createStandardLabels( getMajorTickSpacing() ) );
1335         }
1336         firePropertyChange("paintLabels", oldValue, paintLabels);
1337         if (paintLabels != oldValue) {
1338             revalidate();
1339             repaint();
1340         }
1341     }
1342 
1343 
1344     /**
1345      * See readObject() and writeObject() in JComponent for more
1346      * information about serialization in Swing.
1347      */
writeObject(ObjectOutputStream s)1348     private void writeObject(ObjectOutputStream s) throws IOException {
1349         s.defaultWriteObject();
1350         if (getUIClassID().equals(uiClassID)) {
1351             byte count = JComponent.getWriteObjCounter(this);
1352             JComponent.setWriteObjCounter(this, --count);
1353             if (count == 0 && ui != null) {
1354                 ui.installUI(this);
1355             }
1356         }
1357     }
1358 
1359 
1360     /**
1361      * Returns a string representation of this JSlider. This method
1362      * is intended to be used only for debugging purposes, and the
1363      * content and format of the returned string may vary between
1364      * implementations. The returned string may be empty but may not
1365      * be <code>null</code>.
1366      *
1367      * @return  a string representation of this JSlider.
1368      */
paramString()1369     protected String paramString() {
1370         String paintTicksString = (paintTicks ?
1371                                    "true" : "false");
1372         String paintTrackString = (paintTrack ?
1373                                    "true" : "false");
1374         String paintLabelsString = (paintLabels ?
1375                                     "true" : "false");
1376         String isInvertedString = (isInverted ?
1377                                    "true" : "false");
1378         String snapToTicksString = (snapToTicks ?
1379                                     "true" : "false");
1380         String snapToValueString = (snapToValue ?
1381                                     "true" : "false");
1382         String orientationString = (orientation == HORIZONTAL ?
1383                                     "HORIZONTAL" : "VERTICAL");
1384 
1385         return super.paramString() +
1386         ",isInverted=" + isInvertedString +
1387         ",majorTickSpacing=" + majorTickSpacing +
1388         ",minorTickSpacing=" + minorTickSpacing +
1389         ",orientation=" + orientationString +
1390         ",paintLabels=" + paintLabelsString +
1391         ",paintTicks=" + paintTicksString +
1392         ",paintTrack=" + paintTrackString +
1393         ",snapToTicks=" + snapToTicksString +
1394         ",snapToValue=" + snapToValueString;
1395     }
1396 
1397 
1398 /////////////////
1399 // Accessibility support
1400 ////////////////
1401 
1402     /**
1403      * Gets the AccessibleContext associated with this JSlider.
1404      * For sliders, the AccessibleContext takes the form of an
1405      * AccessibleJSlider.
1406      * A new AccessibleJSlider instance is created if necessary.
1407      *
1408      * @return an AccessibleJSlider that serves as the
1409      *         AccessibleContext of this JSlider
1410      */
getAccessibleContext()1411     public AccessibleContext getAccessibleContext() {
1412         if (accessibleContext == null) {
1413             accessibleContext = new AccessibleJSlider();
1414         }
1415         return accessibleContext;
1416     }
1417 
1418     /**
1419      * This class implements accessibility support for the
1420      * <code>JSlider</code> class.  It provides an implementation of the
1421      * Java Accessibility API appropriate to slider user-interface elements.
1422      * <p>
1423      * <strong>Warning:</strong>
1424      * Serialized objects of this class will not be compatible with
1425      * future Swing releases. The current serialization support is
1426      * appropriate for short term storage or RMI between applications running
1427      * the same version of Swing.  As of 1.4, support for long term storage
1428      * of all JavaBeans&trade;
1429      * has been added to the <code>java.beans</code> package.
1430      * Please see {@link java.beans.XMLEncoder}.
1431      */
1432     protected class AccessibleJSlider extends AccessibleJComponent
1433     implements AccessibleValue {
1434 
1435         /**
1436          * Get the state set of this object.
1437          *
1438          * @return an instance of AccessibleState containing the current state
1439          * of the object
1440          * @see AccessibleState
1441          */
getAccessibleStateSet()1442         public AccessibleStateSet getAccessibleStateSet() {
1443             AccessibleStateSet states = super.getAccessibleStateSet();
1444             if (getValueIsAdjusting()) {
1445                 states.add(AccessibleState.BUSY);
1446             }
1447             if (getOrientation() == VERTICAL) {
1448                 states.add(AccessibleState.VERTICAL);
1449             }
1450             else {
1451                 states.add(AccessibleState.HORIZONTAL);
1452             }
1453             return states;
1454         }
1455 
1456         /**
1457          * Get the role of this object.
1458          *
1459          * @return an instance of AccessibleRole describing the role of the object
1460          */
getAccessibleRole()1461         public AccessibleRole getAccessibleRole() {
1462             return AccessibleRole.SLIDER;
1463         }
1464 
1465         /**
1466          * Get the AccessibleValue associated with this object.  In the
1467          * implementation of the Java Accessibility API for this class,
1468          * return this object, which is responsible for implementing the
1469          * AccessibleValue interface on behalf of itself.
1470          *
1471          * @return this object
1472          */
getAccessibleValue()1473         public AccessibleValue getAccessibleValue() {
1474             return this;
1475         }
1476 
1477         /**
1478          * Get the accessible value of this object.
1479          *
1480          * @return The current value of this object.
1481          */
getCurrentAccessibleValue()1482         public Number getCurrentAccessibleValue() {
1483             return Integer.valueOf(getValue());
1484         }
1485 
1486         /**
1487          * Set the value of this object as a Number.
1488          *
1489          * @return True if the value was set.
1490          */
setCurrentAccessibleValue(Number n)1491         public boolean setCurrentAccessibleValue(Number n) {
1492             // TIGER - 4422535
1493             if (n == null) {
1494                 return false;
1495             }
1496             setValue(n.intValue());
1497             return true;
1498         }
1499 
1500         /**
1501          * Get the minimum accessible value of this object.
1502          *
1503          * @return The minimum value of this object.
1504          */
getMinimumAccessibleValue()1505         public Number getMinimumAccessibleValue() {
1506             return Integer.valueOf(getMinimum());
1507         }
1508 
1509         /**
1510          * Get the maximum accessible value of this object.
1511          *
1512          * @return The maximum value of this object.
1513          */
getMaximumAccessibleValue()1514         public Number getMaximumAccessibleValue() {
1515             // TIGER - 4422362
1516             BoundedRangeModel model = JSlider.this.getModel();
1517             return Integer.valueOf(model.getMaximum() - model.getExtent());
1518         }
1519     } // AccessibleJSlider
1520 }
1521