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