1 /*
   2  * Copyright (c) 1997, 2018, 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 package javax.swing;
  26 
  27 import java.io.Serializable;
  28 import java.awt.Component;
  29 import java.awt.Adjustable;
  30 import java.awt.Dimension;
  31 import java.awt.event.AdjustmentListener;
  32 import java.awt.event.AdjustmentEvent;
  33 import java.beans.JavaBean;
  34 import java.beans.BeanProperty;
  35 
  36 import javax.swing.event.*;
  37 import javax.swing.plaf.*;
  38 import javax.accessibility.*;
  39 
  40 import java.io.ObjectOutputStream;
  41 import java.io.IOException;
  42 
  43 /**
  44  * An implementation of a scrollbar. The user positions the knob in the
  45  * scrollbar to determine the contents of the viewing area. The
  46  * program typically adjusts the display so that the end of the
  47  * scrollbar represents the end of the displayable contents, or 100%
  48  * of the contents. The start of the scrollbar is the beginning of the
  49  * displayable contents, or 0%. The position of the knob within
  50  * those bounds then translates to the corresponding percentage of
  51  * the displayable contents.
  52  * <p>
  53  * Typically, as the position of the knob in the scrollbar changes
  54  * a corresponding change is made to the position of the JViewport on
  55  * the underlying view, changing the contents of the JViewport.
  56  * <p>
  57  * <strong>Warning:</strong> Swing is not thread safe. For more
  58  * information see <a
  59  * href="package-summary.html#threading">Swing's Threading
  60  * Policy</a>.
  61  * <p>
  62  * <strong>Warning:</strong>
  63  * Serialized objects of this class will not be compatible with
  64  * future Swing releases. The current serialization support is
  65  * appropriate for short term storage or RMI between applications running
  66  * the same version of Swing.  As of 1.4, support for long term storage
  67  * of all JavaBeans
  68  * has been added to the <code>java.beans</code> package.
  69  * Please see {@link java.beans.XMLEncoder}.
  70  *
  71  * @see JScrollPane
  72  *
  73  * @author David Kloba
  74  * @since 1.2
  75  */
  76 @JavaBean(defaultProperty = "UI", description = "A component that helps determine the visible content range of an area.")
  77 @SwingContainer(false)
  78 @SuppressWarnings("serial") // Same-version serialization only
  79 public class JScrollBar extends JComponent implements Adjustable, Accessible
  80 {
  81     /**
  82      * @see #getUIClassID
  83      * @see #readObject
  84      */
  85     private static final String uiClassID = "ScrollBarUI";
  86 
  87     /**
  88      * All changes from the model are treated as though the user moved
  89      * the scrollbar knob.
  90      */
  91     private ChangeListener fwdAdjustmentEvents = new ModelListener();
  92 
  93 
  94     /**
  95      * The model that represents the scrollbar's minimum, maximum, extent
  96      * (aka "visibleAmount") and current value.
  97      * @see #setModel
  98      */
  99     protected BoundedRangeModel model;
 100 
 101 
 102     /**
 103      * @see #setOrientation
 104      */
 105     protected int orientation;
 106 
 107 
 108     /**
 109      * @see #setUnitIncrement
 110      */
 111     protected int unitIncrement;
 112 
 113 
 114     /**
 115      * @see #setBlockIncrement
 116      */
 117     protected int blockIncrement;
 118 
 119 
 120     private void checkOrientation(int orientation) {
 121         switch (orientation) {
 122         case VERTICAL:
 123         case HORIZONTAL:
 124             break;
 125         default:
 126             throw new IllegalArgumentException("orientation must be one of: VERTICAL, HORIZONTAL");
 127         }
 128     }
 129 
 130 
 131     /**
 132      * Creates a scrollbar with the specified orientation,
 133      * value, extent, minimum, and maximum.
 134      * The "extent" is the size of the viewable area. It is also known
 135      * as the "visible amount".
 136      * <p>
 137      * Note: Use <code>setBlockIncrement</code> to set the block
 138      * increment to a size slightly smaller than the view's extent.
 139      * That way, when the user jumps the knob to an adjacent position,
 140      * one or two lines of the original contents remain in view.
 141      *
 142      * @exception IllegalArgumentException if orientation is not one of VERTICAL, HORIZONTAL
 143      *
 144      * @see #setOrientation
 145      * @see #setValue
 146      * @see #setVisibleAmount
 147      * @see #setMinimum
 148      * @see #setMaximum
 149      *
 150      * @param orientation an orientation of the {@code JScrollBar}
 151      * @param value an int giving the current value
 152      * @param extent an int giving the amount by which the value can "jump"
 153      * @param min an int giving the minimum value
 154      * @param max an int giving the maximum value
 155      */
 156     public JScrollBar(int orientation, int value, int extent, int min, int max)
 157     {
 158         checkOrientation(orientation);
 159         this.unitIncrement = 1;
 160         this.blockIncrement = (extent == 0) ? 1 : extent;
 161         this.orientation = orientation;
 162         this.model = new DefaultBoundedRangeModel(value, extent, min, max);
 163         this.model.addChangeListener(fwdAdjustmentEvents);
 164         setRequestFocusEnabled(false);
 165         updateUI();
 166     }
 167 
 168 
 169     /**
 170      * Creates a scrollbar with the specified orientation
 171      * and the following initial values:
 172      * <pre>
 173      * minimum = 0
 174      * maximum = 100
 175      * value = 0
 176      * extent = 10
 177      * </pre>
 178      *
 179      * @param orientation an orientation of the {@code JScrollBar}
 180      */
 181     public JScrollBar(int orientation) {
 182         this(orientation, 0, 10, 0, 100);
 183     }
 184 
 185 
 186     /**
 187      * Creates a vertical scrollbar with the following initial values:
 188      * <pre>
 189      * minimum = 0
 190      * maximum = 100
 191      * value = 0
 192      * extent = 10
 193      * </pre>
 194      */
 195     public JScrollBar() {
 196         this(VERTICAL);
 197     }
 198 
 199 
 200     /**
 201      * Sets the {@literal L&F} object that renders this component.
 202      *
 203      * @param ui  the <code>ScrollBarUI</code> {@literal L&F} object
 204      * @see UIDefaults#getUI
 205      * @since 1.4
 206      */
 207     @BeanProperty(hidden = true, visualUpdate = true, description
 208             = "The UI object that implements the Component's LookAndFeel")
 209     public void setUI(ScrollBarUI ui) {
 210         super.setUI(ui);
 211     }
 212 
 213 
 214     /**
 215      * Returns the delegate that implements the look and feel for
 216      * this component.
 217      *
 218      * @return the scroll bar's current UI.
 219      * @see JComponent#setUI
 220      */
 221     public ScrollBarUI getUI() {
 222         return (ScrollBarUI)ui;
 223     }
 224 
 225 
 226     /**
 227      * Overrides <code>JComponent.updateUI</code>.
 228      * @see JComponent#updateUI
 229      */
 230     public void updateUI() {
 231         setUI((ScrollBarUI)UIManager.getUI(this));
 232     }
 233 
 234 
 235     /**
 236      * Returns the name of the LookAndFeel class for this component.
 237      *
 238      * @return the string "ScrollBarUI"
 239      * @see JComponent#getUIClassID
 240      * @see UIDefaults#getUI
 241      */
 242     @BeanProperty(bound = false)
 243     public String getUIClassID() {
 244         return uiClassID;
 245     }
 246 
 247 
 248 
 249     /**
 250      * Returns the component's orientation (horizontal or vertical).
 251      *
 252      * @return VERTICAL or HORIZONTAL
 253      * @see #setOrientation
 254      * @see java.awt.Adjustable#getOrientation
 255      */
 256     public int getOrientation() {
 257         return orientation;
 258     }
 259 
 260 
 261     /**
 262      * Set the scrollbar's orientation to either VERTICAL or
 263      * HORIZONTAL.
 264      *
 265      * @param orientation an orientation of the {@code JScrollBar}
 266      * @exception IllegalArgumentException if orientation is not one of VERTICAL, HORIZONTAL
 267      * @see #getOrientation
 268      */
 269     @BeanProperty(preferred = true, visualUpdate = true, enumerationValues = {
 270             "JScrollBar.VERTICAL",
 271             "JScrollBar.HORIZONTAL"}, description
 272             = "The scrollbar's orientation.")
 273     public void setOrientation(int orientation)
 274     {
 275         checkOrientation(orientation);
 276         int oldValue = this.orientation;
 277         this.orientation = orientation;
 278         firePropertyChange("orientation", oldValue, orientation);
 279 
 280         if ((oldValue != orientation) && (accessibleContext != null)) {
 281             accessibleContext.firePropertyChange(
 282                     AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
 283                     ((oldValue == VERTICAL)
 284                      ? AccessibleState.VERTICAL : AccessibleState.HORIZONTAL),
 285                     ((orientation == VERTICAL)
 286                      ? AccessibleState.VERTICAL : AccessibleState.HORIZONTAL));
 287         }
 288         if (orientation != oldValue) {
 289             revalidate();
 290         }
 291     }
 292 
 293 
 294     /**
 295      * Returns data model that handles the scrollbar's four
 296      * fundamental properties: minimum, maximum, value, extent.
 297      *
 298      * @return the data model
 299      *
 300      * @see #setModel
 301      */
 302     public BoundedRangeModel getModel() {
 303         return model;
 304     }
 305 
 306 
 307     /**
 308      * Sets the model that handles the scrollbar's four
 309      * fundamental properties: minimum, maximum, value, extent.
 310      *
 311      * @param newModel a new model
 312      * @see #getModel
 313      */
 314     @BeanProperty(expert = true, description
 315             = "The scrollbar's BoundedRangeModel.")
 316     public void setModel(BoundedRangeModel newModel) {
 317         Integer oldValue = null;
 318         BoundedRangeModel oldModel = model;
 319         if (model != null) {
 320             model.removeChangeListener(fwdAdjustmentEvents);
 321             oldValue = Integer.valueOf(model.getValue());
 322         }
 323         model = newModel;
 324         if (model != null) {
 325             model.addChangeListener(fwdAdjustmentEvents);
 326         }
 327 
 328         firePropertyChange("model", oldModel, model);
 329 
 330         if (accessibleContext != null) {
 331             accessibleContext.firePropertyChange(
 332                     AccessibleContext.ACCESSIBLE_VALUE_PROPERTY,
 333                     oldValue, model.getValue());
 334         }
 335     }
 336 
 337 
 338     /**
 339      * Returns the amount to change the scrollbar's value by,
 340      * given a unit up/down request.  A ScrollBarUI implementation
 341      * typically calls this method when the user clicks on a scrollbar
 342      * up/down arrow and uses the result to update the scrollbar's
 343      * value.   Subclasses may override this method to compute
 344      * a value, e.g. the change required to scroll one
 345      * (variable height) line of text or one row in a table.
 346      * <p>
 347      * The JScrollPane component creates scrollbars (by default)
 348      * that override this method and delegate to the viewports
 349      * Scrollable view, if it has one.  The Scrollable interface
 350      * provides a more specialized version of this method.
 351      * <p>
 352      * Some look and feel implementations that provide custom scrolling
 353      * behavior ignore this property.
 354      *
 355      * @param direction is -1 or 1 for up/down respectively
 356      * @return the value of the unitIncrement property
 357      * @see #setUnitIncrement
 358      * @see #setValue
 359      * @see Scrollable#getScrollableUnitIncrement
 360      */
 361     public int getUnitIncrement(int direction) {
 362         return unitIncrement;
 363     }
 364 
 365 
 366     /**
 367      * Sets the unitIncrement property.
 368      * <p>
 369      * Note, that if the argument is equal to the value of Integer.MIN_VALUE,
 370      * then most look and feel implementations will not provide scrolling
 371      * to the right/down.
 372      * <p>
 373      * Some look and feel implementations that provide custom scrolling
 374      * behavior ignore this property.
 375      *
 376      * @see #getUnitIncrement
 377      */
 378     @BeanProperty(preferred = true, description
 379             = "The scrollbar's unit increment.")
 380     public void setUnitIncrement(int unitIncrement) {
 381         int oldValue = this.unitIncrement;
 382         this.unitIncrement = unitIncrement;
 383         firePropertyChange("unitIncrement", oldValue, unitIncrement);
 384     }
 385 
 386 
 387     /**
 388      * Returns the amount to change the scrollbar's value by,
 389      * given a block (usually "page") up/down request.  A ScrollBarUI
 390      * implementation typically calls this method when the user clicks
 391      * outside the scrollbar "knob" to scroll up or down by a large amount.
 392      * Subclasses may override this method to compute a
 393      * value, e.g. the change required to scroll one paragraph
 394      * in a text document.
 395      * <p>
 396      * The JScrollPane component creates scrollbars (by default)
 397      * that override this method and delegate to the viewports
 398      * Scrollable view, if it has one.  The Scrollable interface
 399      * provides a more specialized version of this method.
 400      * <p>
 401      * Some look and feel implementations that provide custom scrolling
 402      * behavior ignore this property.
 403      *
 404      * @param direction is -1 or 1 for up/down respectively
 405      * @return the value of the blockIncrement property
 406      * @see #setBlockIncrement
 407      * @see #setValue
 408      * @see Scrollable#getScrollableBlockIncrement
 409      */
 410     public int getBlockIncrement(int direction) {
 411         return blockIncrement;
 412     }
 413 
 414 
 415     /**
 416      * Sets the blockIncrement property.
 417      * <p>
 418      * Note, that if the argument is equal to the value of Integer.MIN_VALUE,
 419      * then most look and feel implementations will not provide scrolling
 420      * to the right/down.
 421      * <p>
 422      * Some look and feel implementations that provide custom scrolling
 423      * behavior ignore this property.
 424      *
 425      * @see #getBlockIncrement()
 426      */
 427     @BeanProperty(preferred = true, description
 428             = "The scrollbar's block increment.")
 429     public void setBlockIncrement(int blockIncrement) {
 430         int oldValue = this.blockIncrement;
 431         this.blockIncrement = blockIncrement;
 432         firePropertyChange("blockIncrement", oldValue, blockIncrement);
 433     }
 434 
 435 
 436     /**
 437      * For backwards compatibility with java.awt.Scrollbar.
 438      * @see Adjustable#getUnitIncrement
 439      * @see #getUnitIncrement(int)
 440      */
 441     public int getUnitIncrement() {
 442         return unitIncrement;
 443     }
 444 
 445 
 446     /**
 447      * For backwards compatibility with java.awt.Scrollbar.
 448      * @see Adjustable#getBlockIncrement
 449      * @see #getBlockIncrement(int)
 450      */
 451     public int getBlockIncrement() {
 452         return blockIncrement;
 453     }
 454 
 455 
 456     /**
 457      * Returns the scrollbar's value.
 458      * @return the model's value property
 459      * @see #setValue
 460      */
 461     public int getValue() {
 462         return getModel().getValue();
 463     }
 464 
 465 
 466     /**
 467      * Sets the scrollbar's value.  This method just forwards the value
 468      * to the model.
 469      *
 470      * @see #getValue
 471      * @see BoundedRangeModel#setValue
 472      */
 473     @BeanProperty(bound = false, preferred = true, description
 474             = "The scrollbar's current value.")
 475     public void setValue(int value) {
 476         BoundedRangeModel m = getModel();
 477         int oldValue = m.getValue();
 478         m.setValue(value);
 479 
 480         if (accessibleContext != null) {
 481             accessibleContext.firePropertyChange(
 482                     AccessibleContext.ACCESSIBLE_VALUE_PROPERTY,
 483                     Integer.valueOf(oldValue),
 484                     Integer.valueOf(m.getValue()));
 485         }
 486     }
 487 
 488 
 489     /**
 490      * Returns the scrollbar's extent, aka its "visibleAmount".  In many
 491      * scrollbar look and feel implementations the size of the
 492      * scrollbar "knob" or "thumb" is proportional to the extent.
 493      *
 494      * @return the value of the model's extent property
 495      * @see #setVisibleAmount
 496      */
 497     public int getVisibleAmount() {
 498         return getModel().getExtent();
 499     }
 500 
 501 
 502     /**
 503      * Set the model's extent property.
 504      *
 505      * @see #getVisibleAmount
 506      * @see BoundedRangeModel#setExtent
 507      */
 508     @BeanProperty(bound = false, preferred = true, description
 509             = "The amount of the view that is currently visible.")
 510     public void setVisibleAmount(int extent) {
 511         getModel().setExtent(extent);
 512     }
 513 
 514 
 515     /**
 516      * Returns the minimum value supported by the scrollbar
 517      * (usually zero).
 518      *
 519      * @return the value of the model's minimum property
 520      * @see #setMinimum
 521      */
 522     public int getMinimum() {
 523         return getModel().getMinimum();
 524     }
 525 
 526 
 527     /**
 528      * Sets the model's minimum property.
 529      *
 530      * @see #getMinimum
 531      * @see BoundedRangeModel#setMinimum
 532      */
 533     @BeanProperty(bound = false, preferred = true, description
 534             = "The scrollbar's minimum value.")
 535     public void setMinimum(int minimum) {
 536         getModel().setMinimum(minimum);
 537     }
 538 
 539 
 540     /**
 541      * The maximum value of the scrollbar is maximum - extent.
 542      *
 543      * @return the value of the model's maximum property
 544      * @see #setMaximum
 545      */
 546     public int getMaximum() {
 547         return getModel().getMaximum();
 548     }
 549 
 550 
 551     /**
 552      * Sets the model's maximum property.  Note that the scrollbar's value
 553      * can only be set to maximum - extent.
 554      *
 555      * @see #getMaximum
 556      * @see BoundedRangeModel#setMaximum
 557      */
 558     @BeanProperty(bound = false, preferred = true, description
 559             = "The scrollbar's maximum value.")
 560     public void setMaximum(int maximum) {
 561         getModel().setMaximum(maximum);
 562     }
 563 
 564 
 565     /**
 566      * True if the scrollbar knob is being dragged.
 567      *
 568      * @return the value of the model's valueIsAdjusting property
 569      * @see #setValueIsAdjusting
 570      */
 571     public boolean getValueIsAdjusting() {
 572         return getModel().getValueIsAdjusting();
 573     }
 574 
 575 
 576     /**
 577      * Sets the model's valueIsAdjusting property.  Scrollbar look and
 578      * feel implementations should set this property to true when
 579      * a knob drag begins, and to false when the drag ends.  The
 580      * scrollbar model will not generate ChangeEvents while
 581      * valueIsAdjusting is true.
 582      *
 583      * @param b {@code true} if the upcoming changes to the value property are part of a series
 584      *
 585      * @see #getValueIsAdjusting
 586      * @see BoundedRangeModel#setValueIsAdjusting
 587      */
 588     @BeanProperty(bound = false, expert = true, description
 589             = "True if the scrollbar thumb is being dragged.")
 590     public void setValueIsAdjusting(boolean b) {
 591         BoundedRangeModel m = getModel();
 592         boolean oldValue = m.getValueIsAdjusting();
 593         m.setValueIsAdjusting(b);
 594 
 595         if ((oldValue != b) && (accessibleContext != null)) {
 596             accessibleContext.firePropertyChange(
 597                     AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
 598                     ((oldValue) ? AccessibleState.BUSY : null),
 599                     ((b) ? AccessibleState.BUSY : null));
 600         }
 601     }
 602 
 603 
 604     /**
 605      * Sets the four BoundedRangeModel properties after forcing
 606      * the arguments to obey the usual constraints:
 607      * <pre>
 608      * minimum &le; value &le; value+extent &le; maximum
 609      * </pre>
 610      *
 611      * @param newValue an int giving the current value
 612      * @param newExtent an int giving the amount by which the value can "jump"
 613      * @param newMin an int giving the minimum value
 614      * @param newMax an int giving the maximum value
 615      *
 616      * @see BoundedRangeModel#setRangeProperties
 617      * @see #setValue
 618      * @see #setVisibleAmount
 619      * @see #setMinimum
 620      * @see #setMaximum
 621      */
 622     public void setValues(int newValue, int newExtent, int newMin, int newMax)
 623     {
 624         BoundedRangeModel m = getModel();
 625         int oldValue = m.getValue();
 626         m.setRangeProperties(newValue, newExtent, newMin, newMax, m.getValueIsAdjusting());
 627 
 628         if (accessibleContext != null) {
 629             accessibleContext.firePropertyChange(
 630                     AccessibleContext.ACCESSIBLE_VALUE_PROPERTY,
 631                     Integer.valueOf(oldValue),
 632                     Integer.valueOf(m.getValue()));
 633         }
 634     }
 635 
 636 
 637     /**
 638      * Adds an AdjustmentListener.  Adjustment listeners are notified
 639      * each time the scrollbar's model changes.  Adjustment events are
 640      * provided for backwards compatibility with java.awt.Scrollbar.
 641      * <p>
 642      * Note that the AdjustmentEvents type property will always have a
 643      * placeholder value of AdjustmentEvent.TRACK because all changes
 644      * to a BoundedRangeModels value are considered equivalent.  To change
 645      * the value of a BoundedRangeModel one just sets its value property,
 646      * i.e. model.setValue(123).  No information about the origin of the
 647      * change, e.g. it's a block decrement, is provided.  We don't try to
 648      * fabricate the origin of the change here.
 649      *
 650      * @param l the AdjustmentLister to add
 651      * @see #removeAdjustmentListener
 652      * @see BoundedRangeModel#addChangeListener
 653      */
 654     public void addAdjustmentListener(AdjustmentListener l)   {
 655         listenerList.add(AdjustmentListener.class, l);
 656     }
 657 
 658 
 659     /**
 660      * Removes an AdjustmentEvent listener.
 661      *
 662      * @param l the AdjustmentLister to remove
 663      * @see #addAdjustmentListener
 664      */
 665     public void removeAdjustmentListener(AdjustmentListener l)  {
 666         listenerList.remove(AdjustmentListener.class, l);
 667     }
 668 
 669 
 670     /**
 671      * Returns an array of all the <code>AdjustmentListener</code>s added
 672      * to this JScrollBar with addAdjustmentListener().
 673      *
 674      * @return all of the <code>AdjustmentListener</code>s added or an empty
 675      *         array if no listeners have been added
 676      * @since 1.4
 677      */
 678     @BeanProperty(bound = false)
 679     public AdjustmentListener[] getAdjustmentListeners() {
 680         return listenerList.getListeners(AdjustmentListener.class);
 681     }
 682 
 683 
 684     /**
 685      * Notify listeners that the scrollbar's model has changed.
 686      *
 687      * @param id an integer indicating the type of event.
 688      * @param type an integer indicating the adjustment type.
 689      * @param value the current value of the adjustment
 690      *
 691      * @see #addAdjustmentListener
 692      * @see EventListenerList
 693      */
 694     protected void fireAdjustmentValueChanged(int id, int type, int value) {
 695         fireAdjustmentValueChanged(id, type, value, getValueIsAdjusting());
 696     }
 697 
 698     /**
 699      * Notify listeners that the scrollbar's model has changed.
 700      *
 701      * @see #addAdjustmentListener
 702      * @see EventListenerList
 703      */
 704     private void fireAdjustmentValueChanged(int id, int type, int value,
 705                                             boolean isAdjusting) {
 706         Object[] listeners = listenerList.getListenerList();
 707         AdjustmentEvent e = null;
 708         for (int i = listeners.length - 2; i >= 0; i -= 2) {
 709             if (listeners[i]==AdjustmentListener.class) {
 710                 if (e == null) {
 711                     e = new AdjustmentEvent(this, id, type, value, isAdjusting);
 712                 }
 713                 ((AdjustmentListener)listeners[i+1]).adjustmentValueChanged(e);
 714             }
 715         }
 716     }
 717 
 718 
 719     /**
 720      * This class listens to ChangeEvents on the model and forwards
 721      * AdjustmentEvents for the sake of backwards compatibility.
 722      * Unfortunately there's no way to determine the proper
 723      * type of the AdjustmentEvent as all updates to the model's
 724      * value are considered equivalent.
 725      */
 726     private class ModelListener implements ChangeListener, Serializable {
 727         public void stateChanged(ChangeEvent e)   {
 728             Object obj = e.getSource();
 729             if (obj instanceof BoundedRangeModel) {
 730                 int id = AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED;
 731                 int type = AdjustmentEvent.TRACK;
 732                 BoundedRangeModel model = (BoundedRangeModel)obj;
 733                 int value = model.getValue();
 734                 boolean isAdjusting = model.getValueIsAdjusting();
 735                 fireAdjustmentValueChanged(id, type, value, isAdjusting);
 736             }
 737         }
 738     }
 739 
 740     // PENDING(hmuller) - the next three methods should be removed
 741 
 742     /**
 743      * The scrollbar is flexible along it's scrolling axis and
 744      * rigid along the other axis.
 745      */
 746     public Dimension getMinimumSize() {
 747         Dimension pref = getPreferredSize();
 748         if (orientation == VERTICAL) {
 749             return new Dimension(pref.width, 5);
 750         } else {
 751             return new Dimension(5, pref.height);
 752         }
 753     }
 754 
 755     /**
 756      * The scrollbar is flexible along it's scrolling axis and
 757      * rigid along the other axis.
 758      */
 759     public Dimension getMaximumSize() {
 760         Dimension pref = getPreferredSize();
 761         if (getOrientation() == VERTICAL) {
 762             return new Dimension(pref.width, Short.MAX_VALUE);
 763         } else {
 764             return new Dimension(Short.MAX_VALUE, pref.height);
 765         }
 766     }
 767 
 768     /**
 769      * Enables the component so that the knob position can be changed.
 770      * When the disabled, the knob position cannot be changed.
 771      *
 772      * @param x a boolean value, where true enables the component and
 773      *          false disables it
 774      */
 775     public void setEnabled(boolean x)  {
 776         super.setEnabled(x);
 777         Component[] children = getComponents();
 778         for (Component child : children) {
 779             child.setEnabled(x);
 780         }
 781     }
 782 
 783     /**
 784      * See readObject() and writeObject() in JComponent for more
 785      * information about serialization in Swing.
 786      */
 787     private void writeObject(ObjectOutputStream s) throws IOException {
 788         s.defaultWriteObject();
 789         if (getUIClassID().equals(uiClassID)) {
 790             byte count = JComponent.getWriteObjCounter(this);
 791             JComponent.setWriteObjCounter(this, --count);
 792             if (count == 0 && ui != null) {
 793                 ui.installUI(this);
 794             }
 795         }
 796     }
 797 
 798 
 799     /**
 800      * Returns a string representation of this JScrollBar. This method
 801      * is intended to be used only for debugging purposes, and the
 802      * content and format of the returned string may vary between
 803      * implementations. The returned string may be empty but may not
 804      * be <code>null</code>.
 805      *
 806      * @return  a string representation of this JScrollBar.
 807      */
 808     protected String paramString() {
 809         String orientationString = (orientation == HORIZONTAL ?
 810                                     "HORIZONTAL" : "VERTICAL");
 811 
 812         return super.paramString() +
 813         ",blockIncrement=" + blockIncrement +
 814         ",orientation=" + orientationString +
 815         ",unitIncrement=" + unitIncrement;
 816     }
 817 
 818 /////////////////
 819 // Accessibility support
 820 ////////////////
 821 
 822     /**
 823      * Gets the AccessibleContext associated with this JScrollBar.
 824      * For JScrollBar, the AccessibleContext takes the form of an
 825      * AccessibleJScrollBar.
 826      * A new AccessibleJScrollBar instance is created if necessary.
 827      *
 828      * @return an AccessibleJScrollBar that serves as the
 829      *         AccessibleContext of this JScrollBar
 830      */
 831     @BeanProperty(bound = false)
 832     public AccessibleContext getAccessibleContext() {
 833         if (accessibleContext == null) {
 834             accessibleContext = new AccessibleJScrollBar();
 835         }
 836         return accessibleContext;
 837     }
 838 
 839     /**
 840      * This class implements accessibility support for the
 841      * <code>JScrollBar</code> class.  It provides an implementation of the
 842      * Java Accessibility API appropriate to scroll bar user-interface
 843      * elements.
 844      * <p>
 845      * <strong>Warning:</strong>
 846      * Serialized objects of this class will not be compatible with
 847      * future Swing releases. The current serialization support is
 848      * appropriate for short term storage or RMI between applications running
 849      * the same version of Swing.  As of 1.4, support for long term storage
 850      * of all JavaBeans
 851      * has been added to the <code>java.beans</code> package.
 852      * Please see {@link java.beans.XMLEncoder}.
 853      */
 854     @SuppressWarnings("serial") // Same-version serialization only
 855     protected class AccessibleJScrollBar extends AccessibleJComponent
 856         implements AccessibleValue {
 857 
 858         /**
 859          * Get the state set of this object.
 860          *
 861          * @return an instance of AccessibleState containing the current state
 862          * of the object
 863          * @see AccessibleState
 864          */
 865         public AccessibleStateSet getAccessibleStateSet() {
 866             AccessibleStateSet states = super.getAccessibleStateSet();
 867             if (getValueIsAdjusting()) {
 868                 states.add(AccessibleState.BUSY);
 869             }
 870             if (getOrientation() == VERTICAL) {
 871                 states.add(AccessibleState.VERTICAL);
 872             } else {
 873                 states.add(AccessibleState.HORIZONTAL);
 874             }
 875             return states;
 876         }
 877 
 878         /**
 879          * Get the role of this object.
 880          *
 881          * @return an instance of AccessibleRole describing the role of the
 882          * object
 883          */
 884         public AccessibleRole getAccessibleRole() {
 885             return AccessibleRole.SCROLL_BAR;
 886         }
 887 
 888         /**
 889          * Get the AccessibleValue associated with this object.  In the
 890          * implementation of the Java Accessibility API for this class,
 891          * return this object, which is responsible for implementing the
 892          * AccessibleValue interface on behalf of itself.
 893          *
 894          * @return this object
 895          */
 896         public AccessibleValue getAccessibleValue() {
 897             return this;
 898         }
 899 
 900         /**
 901          * Get the accessible value of this object.
 902          *
 903          * @return The current value of this object.
 904          */
 905         public Number getCurrentAccessibleValue() {
 906             return Integer.valueOf(getValue());
 907         }
 908 
 909         /**
 910          * Set the value of this object as a Number.
 911          *
 912          * @return True if the value was set.
 913          */
 914         public boolean setCurrentAccessibleValue(Number n) {
 915             // TIGER - 4422535
 916             if (n == null) {
 917                 return false;
 918             }
 919             setValue(n.intValue());
 920             return true;
 921         }
 922 
 923         /**
 924          * Get the minimum accessible value of this object.
 925          *
 926          * @return The minimum value of this object.
 927          */
 928         public Number getMinimumAccessibleValue() {
 929             return Integer.valueOf(getMinimum());
 930         }
 931 
 932         /**
 933          * Get the maximum accessible value of this object.
 934          *
 935          * @return The maximum value of this object.
 936          */
 937         public Number getMaximumAccessibleValue() {
 938             // TIGER - 4422362
 939             return model.getMaximum() - model.getExtent();
 940         }
 941 
 942     } // AccessibleJScrollBar
 943 }