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