1 /*
   2  * Copyright (c) 1997, 2014, 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="http://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  * @since 1.2
  81  */
  82 @SuppressWarnings("serial") // Same-version serialization only
  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<Integer, JComponent> 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         setModel(new DefaultBoundedRangeModel(value, 0, min, max));
 277         updateUI();
 278     }
 279 
 280 
 281     /**
 282      * Creates a horizontal slider using the specified
 283      * BoundedRangeModel.
 284      *
 285      * @param brm a {@code BoundedRangeModel} for the slider
 286      */
 287     public JSlider(BoundedRangeModel brm)
 288     {
 289         this.orientation = JSlider.HORIZONTAL;
 290         setModel(brm);
 291         updateUI();
 292     }
 293 
 294 
 295     /**
 296      * Gets the UI object which implements the L&amp;F for this component.
 297      *
 298      * @return the SliderUI object that implements the Slider L&amp;F
 299      */
 300     public SliderUI getUI() {
 301         return(SliderUI)ui;
 302     }
 303 
 304 
 305     /**
 306      * Sets the UI object which implements the L&amp;F for this component.
 307      *
 308      * @param ui the SliderUI L&amp;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&amp;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      *
 369      * @return a instance of new {@code ChangeListener}
 370      * @see #changeListener
 371      * @see #fireStateChanged
 372      * @see javax.swing.event.ChangeListener
 373      * @see javax.swing.BoundedRangeModel
 374      */
 375     protected ChangeListener createChangeListener() {
 376         return new ModelListener();
 377     }
 378 
 379 
 380     /**
 381      * Adds a ChangeListener to the slider.
 382      *
 383      * @param l the ChangeListener to add
 384      * @see #fireStateChanged
 385      * @see #removeChangeListener
 386      */
 387     public void addChangeListener(ChangeListener l) {
 388         listenerList.add(ChangeListener.class, l);
 389     }
 390 
 391 
 392     /**
 393      * Removes a ChangeListener from the slider.
 394      *
 395      * @param l the ChangeListener to remove
 396      * @see #fireStateChanged
 397      * @see #addChangeListener
 398 
 399      */
 400     public void removeChangeListener(ChangeListener l) {
 401         listenerList.remove(ChangeListener.class, l);
 402     }
 403 
 404 
 405     /**
 406      * Returns an array of all the <code>ChangeListener</code>s added
 407      * to this JSlider with addChangeListener().
 408      *
 409      * @return all of the <code>ChangeListener</code>s added or an empty
 410      *         array if no listeners have been added
 411      * @since 1.4
 412      */
 413     public ChangeListener[] getChangeListeners() {
 414         return listenerList.getListeners(ChangeListener.class);
 415     }
 416 
 417 
 418     /**
 419      * Send a {@code ChangeEvent}, whose source is this {@code JSlider}, to
 420      * all {@code ChangeListener}s that have registered interest in
 421      * {@code ChangeEvent}s.
 422      * This method is called each time a {@code ChangeEvent} is received from
 423      * the model.
 424      * <p>
 425      * The event instance is created if necessary, and stored in
 426      * {@code changeEvent}.
 427      *
 428      * @see #addChangeListener
 429      * @see EventListenerList
 430      */
 431     protected void fireStateChanged() {
 432         Object[] listeners = listenerList.getListenerList();
 433         for (int i = listeners.length - 2; i >= 0; i -= 2) {
 434             if (listeners[i]==ChangeListener.class) {
 435                 if (changeEvent == null) {
 436                     changeEvent = new ChangeEvent(this);
 437                 }
 438                 ((ChangeListener)listeners[i+1]).stateChanged(changeEvent);
 439             }
 440         }
 441     }
 442 
 443 
 444     /**
 445      * Returns the {@code BoundedRangeModel} that handles the slider's three
 446      * fundamental properties: minimum, maximum, value.
 447      *
 448      * @return the data model for this component
 449      * @see #setModel
 450      * @see    BoundedRangeModel
 451      */
 452     public BoundedRangeModel getModel() {
 453         return sliderModel;
 454     }
 455 
 456 
 457     /**
 458      * Sets the {@code BoundedRangeModel} that handles the slider's three
 459      * fundamental properties: minimum, maximum, value.
 460      *<p>
 461      * Attempts to pass a {@code null} model to this method result in
 462      * undefined behavior, and, most likely, exceptions.
 463      *
 464      * @param  newModel the new, {@code non-null} <code>BoundedRangeModel</code> to use
 465      *
 466      * @see #getModel
 467      * @see    BoundedRangeModel
 468      * @beaninfo
 469      *       bound: true
 470      * description: The sliders BoundedRangeModel.
 471      */
 472     public void setModel(BoundedRangeModel newModel)
 473     {
 474         BoundedRangeModel oldModel = getModel();
 475 
 476         if (oldModel != null) {
 477             oldModel.removeChangeListener(changeListener);
 478         }
 479 
 480         sliderModel = newModel;
 481 
 482         if (newModel != null) {
 483             newModel.addChangeListener(changeListener);
 484         }
 485 
 486         if (accessibleContext != null) {
 487             accessibleContext.firePropertyChange(
 488                                                 AccessibleContext.ACCESSIBLE_VALUE_PROPERTY,
 489                                                 (oldModel == null
 490                                                  ? null : Integer.valueOf(oldModel.getValue())),
 491                                                 (newModel == null
 492                                                  ? null : Integer.valueOf(newModel.getValue())));
 493         }
 494 
 495         firePropertyChange("model", oldModel, sliderModel);
 496     }
 497 
 498 
 499     /**
 500      * Returns the slider's current value
 501      * from the {@code BoundedRangeModel}.
 502      *
 503      * @return  the current value of the slider
 504      * @see     #setValue
 505      * @see     BoundedRangeModel#getValue
 506      */
 507     public int getValue() {
 508         return getModel().getValue();
 509     }
 510 
 511     /**
 512      * Sets the slider's current value to {@code n}.  This method
 513      * forwards the new value to the model.
 514      * <p>
 515      * The data model (an instance of {@code BoundedRangeModel})
 516      * handles any mathematical
 517      * issues arising from assigning faulty values.  See the
 518      * {@code BoundedRangeModel} documentation for details.
 519      * <p>
 520      * If the new value is different from the previous value,
 521      * all change listeners are notified.
 522      *
 523      * @param   n       the new value
 524      * @see     #getValue
 525      * @see     #addChangeListener
 526      * @see     BoundedRangeModel#setValue
 527      * @beaninfo
 528      *   preferred: true
 529      * description: The sliders current value.
 530      */
 531     public void setValue(int n) {
 532         BoundedRangeModel m = getModel();
 533         int oldValue = m.getValue();
 534         if (oldValue == n) {
 535             return;
 536         }
 537         m.setValue(n);
 538 
 539         if (accessibleContext != null) {
 540             accessibleContext.firePropertyChange(
 541                                                 AccessibleContext.ACCESSIBLE_VALUE_PROPERTY,
 542                                                 Integer.valueOf(oldValue),
 543                                                 Integer.valueOf(m.getValue()));
 544         }
 545     }
 546 
 547 
 548     /**
 549      * Returns the minimum value supported by the slider
 550      * from the <code>BoundedRangeModel</code>.
 551      *
 552      * @return the value of the model's minimum property
 553      * @see #setMinimum
 554      * @see     BoundedRangeModel#getMinimum
 555      */
 556     public int getMinimum() {
 557         return getModel().getMinimum();
 558     }
 559 
 560 
 561     /**
 562      * Sets the slider's minimum value to {@code minimum}.  This method
 563      * forwards the new minimum value to the model.
 564      * <p>
 565      * The data model (an instance of {@code BoundedRangeModel})
 566      * handles any mathematical
 567      * issues arising from assigning faulty values.  See the
 568      * {@code BoundedRangeModel} documentation for details.
 569      * <p>
 570      * If the new minimum value is different from the previous minimum value,
 571      * all change listeners are notified.
 572      *
 573      * @param minimum  the new minimum
 574      * @see #getMinimum
 575      * @see    #addChangeListener
 576      * @see BoundedRangeModel#setMinimum
 577      * @beaninfo
 578      *       bound: true
 579      *   preferred: true
 580      * description: The sliders minimum value.
 581      */
 582     public void setMinimum(int minimum) {
 583         int oldMin = getModel().getMinimum();
 584         getModel().setMinimum(minimum);
 585         firePropertyChange( "minimum", Integer.valueOf( oldMin ), Integer.valueOf( minimum ) );
 586     }
 587 
 588 
 589     /**
 590      * Returns the maximum value supported by the slider
 591      * from the <code>BoundedRangeModel</code>.
 592      *
 593      * @return the value of the model's maximum property
 594      * @see #setMaximum
 595      * @see BoundedRangeModel#getMaximum
 596      */
 597     public int getMaximum() {
 598         return getModel().getMaximum();
 599     }
 600 
 601 
 602     /**
 603      * Sets the slider's maximum value to {@code maximum}.  This method
 604      * forwards the new maximum value to the model.
 605      * <p>
 606      * The data model (an instance of {@code BoundedRangeModel})
 607      * handles any mathematical
 608      * issues arising from assigning faulty values.  See the
 609      * {@code BoundedRangeModel} documentation for details.
 610      * <p>
 611      * If the new maximum value is different from the previous maximum value,
 612      * all change listeners are notified.
 613      *
 614      * @param maximum  the new maximum
 615      * @see #getMaximum
 616      * @see #addChangeListener
 617      * @see BoundedRangeModel#setMaximum
 618      * @beaninfo
 619      *       bound: true
 620      *   preferred: true
 621      * description: The sliders maximum value.
 622      */
 623     public void setMaximum(int maximum) {
 624         int oldMax = getModel().getMaximum();
 625         getModel().setMaximum(maximum);
 626         firePropertyChange( "maximum", Integer.valueOf( oldMax ), Integer.valueOf( maximum ) );
 627     }
 628 
 629 
 630     /**
 631      * Returns the {@code valueIsAdjusting} property from the model.  For
 632      * details on how this is used, see the {@code setValueIsAdjusting}
 633      * documentation.
 634      *
 635      * @return the value of the model's {@code valueIsAdjusting} property
 636      * @see #setValueIsAdjusting
 637      */
 638     public boolean getValueIsAdjusting() {
 639         return getModel().getValueIsAdjusting();
 640     }
 641 
 642 
 643     /**
 644      * Sets the model's {@code valueIsAdjusting} property.  Slider look and
 645      * feel implementations should set this property to {@code true} when
 646      * a knob drag begins, and to {@code false} when the drag ends.
 647      *
 648      * @param b the new value for the {@code valueIsAdjusting} property
 649      * @see   #getValueIsAdjusting
 650      * @see   BoundedRangeModel#setValueIsAdjusting
 651      * @beaninfo
 652      *      expert: true
 653      * description: True if the slider knob is being dragged.
 654      */
 655     public void setValueIsAdjusting(boolean b) {
 656         BoundedRangeModel m = getModel();
 657         boolean oldValue = m.getValueIsAdjusting();
 658         m.setValueIsAdjusting(b);
 659 
 660         if ((oldValue != b) && (accessibleContext != null)) {
 661             accessibleContext.firePropertyChange(
 662                                                 AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
 663                                                 ((oldValue) ? AccessibleState.BUSY : null),
 664                                                 ((b) ? AccessibleState.BUSY : null));
 665         }
 666     }
 667 
 668 
 669     /**
 670      * Returns the "extent" from the <code>BoundedRangeModel</code>.
 671      * This represents the range of values "covered" by the knob.
 672      *
 673      * @return an int representing the extent
 674      * @see #setExtent
 675      * @see BoundedRangeModel#getExtent
 676      */
 677     public int getExtent() {
 678         return getModel().getExtent();
 679     }
 680 
 681 
 682     /**
 683      * Sets the size of the range "covered" by the knob.  Most look
 684      * and feel implementations will change the value by this amount
 685      * if the user clicks on either side of the knob.  This method just
 686      * forwards the new extent value to the model.
 687      * <p>
 688      * The data model (an instance of {@code BoundedRangeModel})
 689      * handles any mathematical
 690      * issues arising from assigning faulty values.  See the
 691      * {@code BoundedRangeModel} documentation for details.
 692      * <p>
 693      * If the new extent value is different from the previous extent value,
 694      * all change listeners are notified.
 695      *
 696      * @param extent the new extent
 697      * @see   #getExtent
 698      * @see   BoundedRangeModel#setExtent
 699      * @beaninfo
 700      *      expert: true
 701      * description: Size of the range covered by the knob.
 702      */
 703     public void setExtent(int extent) {
 704         getModel().setExtent(extent);
 705     }
 706 
 707 
 708     /**
 709      * Return this slider's vertical or horizontal orientation.
 710      * @return {@code SwingConstants.VERTICAL} or
 711      *  {@code SwingConstants.HORIZONTAL}
 712      * @see #setOrientation
 713      */
 714     public int getOrientation() {
 715         return orientation;
 716     }
 717 
 718 
 719     /**
 720      * Set the slider's orientation to either {@code SwingConstants.VERTICAL} or
 721      * {@code SwingConstants.HORIZONTAL}.
 722      *
 723      * @param orientation {@code HORIZONTAL} or {@code VERTICAL}
 724      * @throws IllegalArgumentException if orientation is not one of {@code VERTICAL}, {@code HORIZONTAL}
 725      * @see #getOrientation
 726      * @beaninfo
 727      *    preferred: true
 728      *        bound: true
 729      *    attribute: visualUpdate true
 730      *  description: Set the scrollbars orientation to either VERTICAL or HORIZONTAL.
 731      *         enum: VERTICAL JSlider.VERTICAL
 732      *               HORIZONTAL JSlider.HORIZONTAL
 733      *
 734      */
 735     public void setOrientation(int orientation)
 736     {
 737         checkOrientation(orientation);
 738         int oldValue = this.orientation;
 739         this.orientation = orientation;
 740         firePropertyChange("orientation", oldValue, orientation);
 741 
 742         if ((oldValue != orientation) && (accessibleContext != null)) {
 743             accessibleContext.firePropertyChange(
 744                                                 AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
 745                                                 ((oldValue == VERTICAL)
 746                                                  ? AccessibleState.VERTICAL : AccessibleState.HORIZONTAL),
 747                                                 ((orientation == VERTICAL)
 748                                                  ? AccessibleState.VERTICAL : AccessibleState.HORIZONTAL));
 749         }
 750         if (orientation != oldValue) {
 751             revalidate();
 752         }
 753     }
 754 
 755 
 756     /**
 757      * {@inheritDoc}
 758      *
 759      * @since 1.6
 760      */
 761     public void setFont(Font font) {
 762         super.setFont(font);
 763         updateLabelSizes();
 764     }
 765 
 766     /**
 767      * {@inheritDoc}
 768      * @since 1.7
 769      */
 770     public boolean imageUpdate(Image img, int infoflags, int x, int y, int w, int h) {
 771         if (!isShowing()) {
 772             return false;
 773         }
 774 
 775         // Check that there is a label with such image
 776         Enumeration<JComponent> elements = labelTable.elements();
 777 
 778         while (elements.hasMoreElements()) {
 779             JComponent component = elements.nextElement();
 780 
 781             if (component instanceof JLabel) {
 782                 JLabel label = (JLabel) component;
 783 
 784                 if (SwingUtilities.doesIconReferenceImage(label.getIcon(), img) ||
 785                         SwingUtilities.doesIconReferenceImage(label.getDisabledIcon(), img)) {
 786                     return super.imageUpdate(img, infoflags, x, y, w, h);
 787                 }
 788             }
 789         }
 790 
 791         return false;
 792     }
 793 
 794     /**
 795      * Returns the dictionary of what labels to draw at which values.
 796      *
 797      * @return the <code>Dictionary</code> containing labels and
 798      *    where to draw them
 799      */
 800     public Dictionary<Integer, JComponent> getLabelTable() {
 801 /*
 802         if ( labelTable == null && getMajorTickSpacing() > 0 ) {
 803             setLabelTable( createStandardLabels( getMajorTickSpacing() ) );
 804         }
 805 */
 806         return labelTable;
 807     }
 808 
 809 
 810     /**
 811      * Used to specify what label will be drawn at any given value.
 812      * The key-value pairs are of this format:
 813      * <code>{ Integer value, java.swing.JComponent label }</code>.
 814      * <p>
 815      * An easy way to generate a standard table of value labels is by using the
 816      * {@code createStandardLabels} method.
 817      * <p>
 818      * Once the labels have been set, this method calls {@link #updateLabelUIs}.
 819      * Note that the labels are only painted if the {@code paintLabels}
 820      * property is {@code true}.
 821      *
 822      * @param labels new {@code Dictionary} of labels, or {@code null} to
 823      *        remove all labels
 824      * @see #createStandardLabels(int)
 825      * @see #getLabelTable
 826      * @see #setPaintLabels
 827      * @beaninfo
 828      *       hidden: true
 829      *        bound: true
 830      *    attribute: visualUpdate true
 831      *  description: Specifies what labels will be drawn for any given value.
 832      */
 833     public void setLabelTable( Dictionary<Integer, JComponent> labels ) {
 834         Dictionary<Integer, JComponent> oldTable = labelTable;
 835         labelTable = labels;
 836         updateLabelUIs();
 837         firePropertyChange("labelTable", oldTable, labelTable );
 838         if (labels != oldTable) {
 839             revalidate();
 840             repaint();
 841         }
 842     }
 843 
 844 
 845     /**
 846      * Updates the UIs for the labels in the label table by calling
 847      * {@code updateUI} on each label.  The UIs are updated from
 848      * the current look and feel.  The labels are also set to their
 849      * preferred size.
 850      *
 851      * @see #setLabelTable
 852      * @see JComponent#updateUI
 853      */
 854     protected void updateLabelUIs() {
 855         Dictionary<Integer, JComponent> labelTable = getLabelTable();
 856 
 857         if (labelTable == null) {
 858             return;
 859         }
 860         Enumeration<Integer> labels = labelTable.keys();
 861         while ( labels.hasMoreElements() ) {
 862             JComponent component = labelTable.get(labels.nextElement());
 863             component.updateUI();
 864             component.setSize(component.getPreferredSize());
 865         }
 866     }
 867 
 868     private void updateLabelSizes() {
 869         Dictionary<Integer, JComponent> labelTable = getLabelTable();
 870         if (labelTable != null) {
 871             Enumeration<JComponent> labels = labelTable.elements();
 872             while (labels.hasMoreElements()) {
 873                 JComponent component = labels.nextElement();
 874                 component.setSize(component.getPreferredSize());
 875             }
 876         }
 877     }
 878 
 879 
 880     /**
 881      * Creates a {@code Hashtable} of numerical text labels, starting at the
 882      * slider minimum, and using the increment specified.
 883      * For example, if you call <code>createStandardLabels( 10 )</code>
 884      * and the slider minimum is zero,
 885      * then labels will be created for the values 0, 10, 20, 30, and so on.
 886      * <p>
 887      * For the labels to be drawn on the slider, the returned {@code Hashtable}
 888      * must be passed into {@code setLabelTable}, and {@code setPaintLabels}
 889      * must be set to {@code true}.
 890      * <p>
 891      * For further details on the makeup of the returned {@code Hashtable}, see
 892      * the {@code setLabelTable} documentation.
 893      *
 894      * @param  increment  distance between labels in the generated hashtable
 895      * @return a new {@code Hashtable} of labels
 896      * @see #setLabelTable
 897      * @see #setPaintLabels
 898      * @throws IllegalArgumentException if {@code increment} is less than or
 899      *          equal to zero
 900      */
 901     public Hashtable<Integer, JComponent> createStandardLabels( int increment ) {
 902         return createStandardLabels( increment, getMinimum() );
 903     }
 904 
 905 
 906     /**
 907      * Creates a {@code Hashtable} of numerical text labels, starting at the
 908      * starting point specified, and using the increment specified.
 909      * For example, if you call
 910      * <code>createStandardLabels( 10, 2 )</code>,
 911      * then labels will be created for the values 2, 12, 22, 32, and so on.
 912      * <p>
 913      * For the labels to be drawn on the slider, the returned {@code Hashtable}
 914      * must be passed into {@code setLabelTable}, and {@code setPaintLabels}
 915      * must be set to {@code true}.
 916      * <p>
 917      * For further details on the makeup of the returned {@code Hashtable}, see
 918      * the {@code setLabelTable} documentation.
 919      *
 920      * @param  increment  distance between labels in the generated hashtable
 921      * @param  start      value at which the labels will begin
 922      * @return a new {@code Hashtable} of labels
 923      * @see #setLabelTable
 924      * @see #setPaintLabels
 925      * @exception IllegalArgumentException if {@code start} is
 926      *          out of range, or if {@code increment} is less than or equal
 927      *          to zero
 928      */
 929     public Hashtable<Integer, JComponent> createStandardLabels( int increment, int start ) {
 930         if ( start > getMaximum() || start < getMinimum() ) {
 931             throw new IllegalArgumentException( "Slider label start point out of range." );
 932         }
 933 
 934         if ( increment <= 0 ) {
 935             throw new IllegalArgumentException( "Label incremement must be > 0" );
 936         }
 937 
 938         class SmartHashtable extends Hashtable<Integer, JComponent> implements PropertyChangeListener {
 939             int increment = 0;
 940             int start = 0;
 941             boolean startAtMin = false;
 942 
 943             class LabelUIResource extends JLabel implements UIResource {
 944                 public LabelUIResource( String text, int alignment ) {
 945                     super( text, alignment );
 946                     setName("Slider.label");
 947                 }
 948 
 949                 public Font getFont() {
 950                     Font font = super.getFont();
 951                     if (font != null && !(font instanceof UIResource)) {
 952                         return font;
 953                     }
 954                     return JSlider.this.getFont();
 955                 }
 956 
 957                 public Color getForeground() {
 958                     Color fg = super.getForeground();
 959                     if (fg != null && !(fg instanceof UIResource)) {
 960                         return fg;
 961                     }
 962                     if (!(JSlider.this.getForeground() instanceof UIResource)) {
 963                         return JSlider.this.getForeground();
 964                     }
 965                     return fg;
 966                 }
 967             }
 968 
 969             public SmartHashtable( int increment, int start ) {
 970                 super();
 971                 this.increment = increment;
 972                 this.start = start;
 973                 startAtMin = start == getMinimum();
 974                 createLabels();
 975             }
 976 
 977             public void propertyChange( PropertyChangeEvent e ) {
 978                 if ( e.getPropertyName().equals( "minimum" ) && startAtMin ) {
 979                     start = getMinimum();
 980                 }
 981 
 982                 if ( e.getPropertyName().equals( "minimum" ) ||
 983                      e.getPropertyName().equals( "maximum" ) ) {
 984 
 985                     Enumeration<Integer> keys = getLabelTable().keys();
 986                     Hashtable<Integer, JComponent> hashtable = new Hashtable<>();
 987 
 988                     // Save the labels that were added by the developer
 989                     while ( keys.hasMoreElements() ) {
 990                         Integer key = keys.nextElement();
 991                         JComponent value = labelTable.get(key);
 992                         if ( !(value instanceof LabelUIResource) ) {
 993                             hashtable.put( key, value );
 994                         }
 995                     }
 996 
 997                     clear();
 998                     createLabels();
 999 
1000                     // Add the saved labels
1001                     keys = hashtable.keys();
1002                     while ( keys.hasMoreElements() ) {
1003                         Integer key = keys.nextElement();
1004                         put( key, hashtable.get( key ) );
1005                     }
1006 
1007                     ((JSlider)e.getSource()).setLabelTable( this );
1008                 }
1009             }
1010 
1011             void createLabels() {
1012                 for ( int labelIndex = start; labelIndex <= getMaximum(); labelIndex += increment ) {
1013                     put( Integer.valueOf( labelIndex ), new LabelUIResource( ""+labelIndex, JLabel.CENTER ) );
1014                 }
1015             }
1016         }
1017 
1018         SmartHashtable table = new SmartHashtable( increment, start );
1019 
1020         Dictionary<Integer, JComponent> labelTable = getLabelTable();
1021 
1022         if (labelTable != null && (labelTable instanceof PropertyChangeListener)) {
1023             removePropertyChangeListener((PropertyChangeListener) labelTable);
1024         }
1025 
1026         addPropertyChangeListener( table );
1027 
1028         return table;
1029     }
1030 
1031 
1032     /**
1033      * Returns true if the value-range shown for the slider is reversed,
1034      *
1035      * @return true if the slider values are reversed from their normal order
1036      * @see #setInverted
1037      */
1038     public boolean getInverted() {
1039         return isInverted;
1040     }
1041 
1042 
1043     /**
1044      * Specify true to reverse the value-range shown for the slider and false to
1045      * put the value range in the normal order.  The order depends on the
1046      * slider's <code>ComponentOrientation</code> property.  Normal (non-inverted)
1047      * horizontal sliders with a <code>ComponentOrientation</code> value of
1048      * <code>LEFT_TO_RIGHT</code> have their maximum on the right.
1049      * Normal horizontal sliders with a <code>ComponentOrientation</code> value of
1050      * <code>RIGHT_TO_LEFT</code> have their maximum on the left.  Normal vertical
1051      * sliders have their maximum on the top.  These labels are reversed when the
1052      * slider is inverted.
1053      * <p>
1054      * By default, the value of this property is {@code false}.
1055      *
1056      * @param b  true to reverse the slider values from their normal order
1057      * @beaninfo
1058      *        bound: true
1059      *    attribute: visualUpdate true
1060      *  description: If true reverses the slider values from their normal order
1061      *
1062      */
1063     public void setInverted( boolean b ) {
1064         boolean oldValue = isInverted;
1065         isInverted = b;
1066         firePropertyChange("inverted", oldValue, isInverted);
1067         if (b != oldValue) {
1068             repaint();
1069         }
1070     }
1071 
1072 
1073     /**
1074      * This method returns the major tick spacing.  The number that is returned
1075      * represents the distance, measured in values, between each major tick mark.
1076      * If you have a slider with a range from 0 to 50 and the major tick spacing
1077      * is set to 10, you will get major ticks next to the following values:
1078      * 0, 10, 20, 30, 40, 50.
1079      *
1080      * @return the number of values between major ticks
1081      * @see #setMajorTickSpacing
1082      */
1083     public int getMajorTickSpacing() {
1084         return majorTickSpacing;
1085     }
1086 
1087 
1088     /**
1089      * This method sets the major tick spacing.  The number that is passed in
1090      * represents the distance, measured in values, between each major tick mark.
1091      * If you have a slider with a range from 0 to 50 and the major tick spacing
1092      * is set to 10, you will get major ticks next to the following values:
1093      * 0, 10, 20, 30, 40, 50.
1094      * <p>
1095      * In order for major ticks to be painted, {@code setPaintTicks} must be
1096      * set to {@code true}.
1097      * <p>
1098      * This method will also set up a label table for you.
1099      * If there is not already a label table, and the major tick spacing is
1100      * {@code > 0}, and {@code getPaintLabels} returns
1101      * {@code true}, a standard label table will be generated (by calling
1102      * {@code createStandardLabels}) with labels at the major tick marks.
1103      * For the example above, you would get text labels: "0",
1104      * "10", "20", "30", "40", "50".
1105      * The label table is then set on the slider by calling
1106      * {@code setLabelTable}.
1107      *
1108      * @param  n  new value for the {@code majorTickSpacing} property
1109      * @see #getMajorTickSpacing
1110      * @see #setPaintTicks
1111      * @see #setLabelTable
1112      * @see #createStandardLabels(int)
1113      * @beaninfo
1114      *        bound: true
1115      *    attribute: visualUpdate true
1116      *  description: Sets the number of values between major tick marks.
1117      *
1118      */
1119     public void setMajorTickSpacing(int n) {
1120         int oldValue = majorTickSpacing;
1121         majorTickSpacing = n;
1122         if ( labelTable == null && getMajorTickSpacing() > 0 && getPaintLabels() ) {
1123             setLabelTable( createStandardLabels( getMajorTickSpacing() ) );
1124         }
1125         firePropertyChange("majorTickSpacing", oldValue, majorTickSpacing);
1126         if (majorTickSpacing != oldValue && getPaintTicks()) {
1127             repaint();
1128         }
1129     }
1130 
1131 
1132 
1133     /**
1134      * This method returns the minor tick spacing.  The number that is returned
1135      * represents the distance, measured in values, between each minor tick mark.
1136      * If you have a slider with a range from 0 to 50 and the minor tick spacing
1137      * is set to 10, you will get minor ticks next to the following values:
1138      * 0, 10, 20, 30, 40, 50.
1139      *
1140      * @return the number of values between minor ticks
1141      * @see #getMinorTickSpacing
1142      */
1143     public int getMinorTickSpacing() {
1144         return minorTickSpacing;
1145     }
1146 
1147 
1148     /**
1149      * This method sets the minor tick spacing.  The number that is passed in
1150      * represents the distance, measured in values, between each minor tick mark.
1151      * If you have a slider with a range from 0 to 50 and the minor tick spacing
1152      * is set to 10, you will get minor ticks next to the following values:
1153      * 0, 10, 20, 30, 40, 50.
1154      * <p>
1155      * In order for minor ticks to be painted, {@code setPaintTicks} must be
1156      * set to {@code true}.
1157      *
1158      * @param  n  new value for the {@code minorTickSpacing} property
1159      * @see #getMinorTickSpacing
1160      * @see #setPaintTicks
1161      * @beaninfo
1162      *        bound: true
1163      *    attribute: visualUpdate true
1164      *  description: Sets the number of values between minor tick marks.
1165      */
1166     public void setMinorTickSpacing(int n) {
1167         int oldValue = minorTickSpacing;
1168         minorTickSpacing = n;
1169         firePropertyChange("minorTickSpacing", oldValue, minorTickSpacing);
1170         if (minorTickSpacing != oldValue && getPaintTicks()) {
1171             repaint();
1172         }
1173     }
1174 
1175 
1176     /**
1177      * Returns true if the knob (and the data value it represents)
1178      * resolve to the closest tick mark next to where the user
1179      * positioned the knob.
1180      *
1181      * @return true if the value snaps to the nearest tick mark, else false
1182      * @see #setSnapToTicks
1183      */
1184     public boolean getSnapToTicks() {
1185         return snapToTicks;
1186     }
1187 
1188 
1189     /**
1190      * Returns true if the knob (and the data value it represents)
1191      * resolve to the closest slider value next to where the user
1192      * positioned the knob.
1193      *
1194      * @return true if the value snaps to the nearest slider value, else false
1195      * @see #setSnapToValue
1196      */
1197     boolean getSnapToValue() {
1198         return snapToValue;
1199     }
1200 
1201 
1202     /**
1203      * Specifying true makes the knob (and the data value it represents)
1204      * resolve to the closest tick mark next to where the user
1205      * positioned the knob.
1206      * By default, this property is {@code false}.
1207      *
1208      * @param b  true to snap the knob to the nearest tick mark
1209      * @see #getSnapToTicks
1210      * @beaninfo
1211      *       bound: true
1212      * description: If true snap the knob to the nearest tick mark.
1213      */
1214     public void setSnapToTicks(boolean b) {
1215         boolean oldValue = snapToTicks;
1216         snapToTicks = b;
1217         firePropertyChange("snapToTicks", oldValue, snapToTicks);
1218     }
1219 
1220 
1221     /**
1222      * Specifying true makes the knob (and the data value it represents)
1223      * resolve to the closest slider value next to where the user
1224      * positioned the knob. If the {@code snapToTicks} property has also been
1225      * set to {@code true}, the snap-to-ticks behavior will prevail.
1226      * By default, the snapToValue property is {@code true}.
1227      *
1228      * @param b  true to snap the knob to the nearest slider value
1229      * @see #getSnapToValue
1230      * @see #setSnapToTicks
1231      * @beaninfo
1232      *       bound: true
1233      * description: If true snap the knob to the nearest slider value.
1234      */
1235     void setSnapToValue(boolean b) {
1236         boolean oldValue = snapToValue;
1237         snapToValue = b;
1238         firePropertyChange("snapToValue", oldValue, snapToValue);
1239     }
1240 
1241 
1242     /**
1243      * Tells if tick marks are to be painted.
1244      * @return true if tick marks are painted, else false
1245      * @see #setPaintTicks
1246      */
1247     public boolean getPaintTicks() {
1248         return paintTicks;
1249     }
1250 
1251 
1252     /**
1253      * Determines whether tick marks are painted on the slider.
1254      * By default, this property is {@code false}.
1255      *
1256      * @param  b  whether or not tick marks should be painted
1257      * @see #getPaintTicks
1258      * @beaninfo
1259      *        bound: true
1260      *    attribute: visualUpdate true
1261      *  description: If true tick marks are painted on the slider.
1262      */
1263     public void setPaintTicks(boolean b) {
1264         boolean oldValue = paintTicks;
1265         paintTicks = b;
1266         firePropertyChange("paintTicks", oldValue, paintTicks);
1267         if (paintTicks != oldValue) {
1268             revalidate();
1269             repaint();
1270         }
1271     }
1272 
1273     /**
1274      * Tells if the track (area the slider slides in) is to be painted.
1275      * @return true if track is painted, else false
1276      * @see #setPaintTrack
1277      */
1278     public boolean getPaintTrack() {
1279         return paintTrack;
1280     }
1281 
1282 
1283     /**
1284      * Determines whether the track is painted on the slider.
1285      * By default, this property is {@code true}.
1286      *
1287      * @param  b  whether or not to paint the slider track
1288      * @see #getPaintTrack
1289      * @beaninfo
1290      *        bound: true
1291      *    attribute: visualUpdate true
1292      *  description: If true, the track is painted on the slider.
1293      */
1294     public void setPaintTrack(boolean b) {
1295         boolean oldValue = paintTrack;
1296         paintTrack = b;
1297         firePropertyChange("paintTrack", oldValue, paintTrack);
1298         if (paintTrack != oldValue) {
1299             repaint();
1300         }
1301     }
1302 
1303 
1304     /**
1305      * Tells if labels are to be painted.
1306      * @return true if labels are painted, else false
1307      * @see #setPaintLabels
1308      */
1309     public boolean getPaintLabels() {
1310         return paintLabels;
1311     }
1312 
1313 
1314     /**
1315      * Determines whether labels are painted on the slider.
1316      * <p>
1317      * This method will also set up a label table for you.
1318      * If there is not already a label table, and the major tick spacing is
1319      * {@code > 0},
1320      * a standard label table will be generated (by calling
1321      * {@code createStandardLabels}) with labels at the major tick marks.
1322      * The label table is then set on the slider by calling
1323      * {@code setLabelTable}.
1324      * <p>
1325      * By default, this property is {@code false}.
1326      *
1327      * @param  b  whether or not to paint labels
1328      * @see #getPaintLabels
1329      * @see #getLabelTable
1330      * @see #createStandardLabels(int)
1331      * @beaninfo
1332      *        bound: true
1333      *    attribute: visualUpdate true
1334      *  description: If true labels are painted on the slider.
1335      */
1336     public void setPaintLabels(boolean b) {
1337         boolean oldValue = paintLabels;
1338         paintLabels = b;
1339         if ( labelTable == null && getMajorTickSpacing() > 0 ) {
1340             setLabelTable( createStandardLabels( getMajorTickSpacing() ) );
1341         }
1342         firePropertyChange("paintLabels", oldValue, paintLabels);
1343         if (paintLabels != oldValue) {
1344             revalidate();
1345             repaint();
1346         }
1347     }
1348 
1349 
1350     /**
1351      * See readObject() and writeObject() in JComponent for more
1352      * information about serialization in Swing.
1353      */
1354     private void writeObject(ObjectOutputStream s) throws IOException {
1355         s.defaultWriteObject();
1356         if (getUIClassID().equals(uiClassID)) {
1357             byte count = JComponent.getWriteObjCounter(this);
1358             JComponent.setWriteObjCounter(this, --count);
1359             if (count == 0 && ui != null) {
1360                 ui.installUI(this);
1361             }
1362         }
1363     }
1364 
1365 
1366     /**
1367      * Returns a string representation of this JSlider. This method
1368      * is intended to be used only for debugging purposes, and the
1369      * content and format of the returned string may vary between
1370      * implementations. The returned string may be empty but may not
1371      * be <code>null</code>.
1372      *
1373      * @return  a string representation of this JSlider.
1374      */
1375     protected String paramString() {
1376         String paintTicksString = (paintTicks ?
1377                                    "true" : "false");
1378         String paintTrackString = (paintTrack ?
1379                                    "true" : "false");
1380         String paintLabelsString = (paintLabels ?
1381                                     "true" : "false");
1382         String isInvertedString = (isInverted ?
1383                                    "true" : "false");
1384         String snapToTicksString = (snapToTicks ?
1385                                     "true" : "false");
1386         String snapToValueString = (snapToValue ?
1387                                     "true" : "false");
1388         String orientationString = (orientation == HORIZONTAL ?
1389                                     "HORIZONTAL" : "VERTICAL");
1390 
1391         return super.paramString() +
1392         ",isInverted=" + isInvertedString +
1393         ",majorTickSpacing=" + majorTickSpacing +
1394         ",minorTickSpacing=" + minorTickSpacing +
1395         ",orientation=" + orientationString +
1396         ",paintLabels=" + paintLabelsString +
1397         ",paintTicks=" + paintTicksString +
1398         ",paintTrack=" + paintTrackString +
1399         ",snapToTicks=" + snapToTicksString +
1400         ",snapToValue=" + snapToValueString;
1401     }
1402 
1403 
1404 /////////////////
1405 // Accessibility support
1406 ////////////////
1407 
1408     /**
1409      * Gets the AccessibleContext associated with this JSlider.
1410      * For sliders, the AccessibleContext takes the form of an
1411      * AccessibleJSlider.
1412      * A new AccessibleJSlider instance is created if necessary.
1413      *
1414      * @return an AccessibleJSlider that serves as the
1415      *         AccessibleContext of this JSlider
1416      */
1417     public AccessibleContext getAccessibleContext() {
1418         if (accessibleContext == null) {
1419             accessibleContext = new AccessibleJSlider();
1420         }
1421         return accessibleContext;
1422     }
1423 
1424     /**
1425      * This class implements accessibility support for the
1426      * <code>JSlider</code> class.  It provides an implementation of the
1427      * Java Accessibility API appropriate to slider user-interface elements.
1428      * <p>
1429      * <strong>Warning:</strong>
1430      * Serialized objects of this class will not be compatible with
1431      * future Swing releases. The current serialization support is
1432      * appropriate for short term storage or RMI between applications running
1433      * the same version of Swing.  As of 1.4, support for long term storage
1434      * of all JavaBeans&trade;
1435      * has been added to the <code>java.beans</code> package.
1436      * Please see {@link java.beans.XMLEncoder}.
1437      */
1438     @SuppressWarnings("serial") // Same-version serialization only
1439     protected class AccessibleJSlider extends AccessibleJComponent
1440     implements AccessibleValue {
1441 
1442         /**
1443          * Get the state set of this object.
1444          *
1445          * @return an instance of AccessibleState containing the current state
1446          * of the object
1447          * @see AccessibleState
1448          */
1449         public AccessibleStateSet getAccessibleStateSet() {
1450             AccessibleStateSet states = super.getAccessibleStateSet();
1451             if (getValueIsAdjusting()) {
1452                 states.add(AccessibleState.BUSY);
1453             }
1454             if (getOrientation() == VERTICAL) {
1455                 states.add(AccessibleState.VERTICAL);
1456             }
1457             else {
1458                 states.add(AccessibleState.HORIZONTAL);
1459             }
1460             return states;
1461         }
1462 
1463         /**
1464          * Get the role of this object.
1465          *
1466          * @return an instance of AccessibleRole describing the role of the object
1467          */
1468         public AccessibleRole getAccessibleRole() {
1469             return AccessibleRole.SLIDER;
1470         }
1471 
1472         /**
1473          * Get the AccessibleValue associated with this object.  In the
1474          * implementation of the Java Accessibility API for this class,
1475          * return this object, which is responsible for implementing the
1476          * AccessibleValue interface on behalf of itself.
1477          *
1478          * @return this object
1479          */
1480         public AccessibleValue getAccessibleValue() {
1481             return this;
1482         }
1483 
1484         /**
1485          * Get the accessible value of this object.
1486          *
1487          * @return The current value of this object.
1488          */
1489         public Number getCurrentAccessibleValue() {
1490             return Integer.valueOf(getValue());
1491         }
1492 
1493         /**
1494          * Set the value of this object as a Number.
1495          *
1496          * @return True if the value was set.
1497          */
1498         public boolean setCurrentAccessibleValue(Number n) {
1499             // TIGER - 4422535
1500             if (n == null) {
1501                 return false;
1502             }
1503             setValue(n.intValue());
1504             return true;
1505         }
1506 
1507         /**
1508          * Get the minimum accessible value of this object.
1509          *
1510          * @return The minimum value of this object.
1511          */
1512         public Number getMinimumAccessibleValue() {
1513             return Integer.valueOf(getMinimum());
1514         }
1515 
1516         /**
1517          * Get the maximum accessible value of this object.
1518          *
1519          * @return The maximum value of this object.
1520          */
1521         public Number getMaximumAccessibleValue() {
1522             // TIGER - 4422362
1523             BoundedRangeModel model = JSlider.this.getModel();
1524             return Integer.valueOf(model.getMaximum() - model.getExtent());
1525         }
1526     } // AccessibleJSlider
1527 }