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