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