1 /*
   2  * Copyright (c) 1996, 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 package java.awt;
  26 
  27 import java.awt.peer.LightweightPeer;
  28 import java.awt.peer.ScrollPanePeer;
  29 import java.awt.event.*;
  30 import javax.accessibility.*;
  31 import sun.awt.ScrollPaneWheelScroller;
  32 import sun.awt.SunToolkit;
  33 
  34 import java.beans.ConstructorProperties;
  35 import java.beans.Transient;
  36 import java.io.ObjectInputStream;
  37 import java.io.ObjectOutputStream;
  38 import java.io.IOException;
  39 
  40 /**
  41  * A container class which implements automatic horizontal and/or
  42  * vertical scrolling for a single child component.  The display
  43  * policy for the scrollbars can be set to:
  44  * <OL>
  45  * <LI>as needed: scrollbars created and shown only when needed by scrollpane
  46  * <LI>always: scrollbars created and always shown by the scrollpane
  47  * <LI>never: scrollbars never created or shown by the scrollpane
  48  * </OL>
  49  * <P>
  50  * The state of the horizontal and vertical scrollbars is represented
  51  * by two <code>ScrollPaneAdjustable</code> objects (one for each
  52  * dimension) which implement the <code>Adjustable</code> interface.
  53  * The API provides methods to access those objects such that the
  54  * attributes on the Adjustable object (such as unitIncrement, value,
  55  * etc.) can be manipulated.
  56  * <P>
  57  * Certain adjustable properties (minimum, maximum, blockIncrement,
  58  * and visibleAmount) are set internally by the scrollpane in accordance
  59  * with the geometry of the scrollpane and its child and these should
  60  * not be set by programs using the scrollpane.
  61  * <P>
  62  * If the scrollbar display policy is defined as "never", then the
  63  * scrollpane can still be programmatically scrolled using the
  64  * setScrollPosition() method and the scrollpane will move and clip
  65  * the child's contents appropriately.  This policy is useful if the
  66  * program needs to create and manage its own adjustable controls.
  67  * <P>
  68  * The placement of the scrollbars is controlled by platform-specific
  69  * properties set by the user outside of the program.
  70  * <P>
  71  * The initial size of this container is set to 100x100, but can
  72  * be reset using setSize().
  73  * <P>
  74  * Scrolling with the wheel on a wheel-equipped mouse is enabled by default.
  75  * This can be disabled using <code>setWheelScrollingEnabled</code>.
  76  * Wheel scrolling can be customized by setting the block and
  77  * unit increment of the horizontal and vertical Adjustables.
  78  * For information on how mouse wheel events are dispatched, see
  79  * the class description for {@link MouseWheelEvent}.
  80  * <P>
  81  * Insets are used to define any space used by scrollbars and any
  82  * borders created by the scroll pane. getInsets() can be used
  83  * to get the current value for the insets.  If the value of
  84  * scrollbarsAlwaysVisible is false, then the value of the insets
  85  * will change dynamically depending on whether the scrollbars are
  86  * currently visible or not.
  87  *
  88  * @author      Tom Ball
  89  * @author      Amy Fowler
  90  * @author      Tim Prinzing
  91  */
  92 public class ScrollPane extends Container implements Accessible {
  93 
  94 
  95     /**
  96      * Initialize JNI field and method IDs
  97      */
  98     private static native void initIDs();
  99 
 100     static {
 101         /* ensure that the necessary native libraries are loaded */
 102         Toolkit.loadLibraries();
 103         if (!GraphicsEnvironment.isHeadless()) {
 104             initIDs();
 105         }
 106     }
 107 
 108     /**
 109      * Specifies that horizontal/vertical scrollbar should be shown
 110      * only when the size of the child exceeds the size of the scrollpane
 111      * in the horizontal/vertical dimension.
 112      */
 113     public static final int SCROLLBARS_AS_NEEDED = 0;
 114 
 115     /**
 116      * Specifies that horizontal/vertical scrollbars should always be
 117      * shown regardless of the respective sizes of the scrollpane and child.
 118      */
 119     public static final int SCROLLBARS_ALWAYS = 1;
 120 
 121     /**
 122      * Specifies that horizontal/vertical scrollbars should never be shown
 123      * regardless of the respective sizes of the scrollpane and child.
 124      */
 125     public static final int SCROLLBARS_NEVER = 2;
 126 
 127     /**
 128      * There are 3 ways in which a scroll bar can be displayed.
 129      * This integer will represent one of these 3 displays -
 130      * (SCROLLBARS_ALWAYS, SCROLLBARS_AS_NEEDED, SCROLLBARS_NEVER)
 131      *
 132      * @serial
 133      * @see #getScrollbarDisplayPolicy
 134      */
 135     private int scrollbarDisplayPolicy;
 136 
 137     /**
 138      * An adjustable vertical scrollbar.
 139      * It is important to note that you must <em>NOT</em> call 3
 140      * <code>Adjustable</code> methods, namely:
 141      * <code>setMinimum()</code>, <code>setMaximum()</code>,
 142      * <code>setVisibleAmount()</code>.
 143      *
 144      * @serial
 145      * @see #getVAdjustable
 146      */
 147     private ScrollPaneAdjustable vAdjustable;
 148 
 149     /**
 150      * An adjustable horizontal scrollbar.
 151      * It is important to note that you must <em>NOT</em> call 3
 152      * <code>Adjustable</code> methods, namely:
 153      * <code>setMinimum()</code>, <code>setMaximum()</code>,
 154      * <code>setVisibleAmount()</code>.
 155      *
 156      * @serial
 157      * @see #getHAdjustable
 158      */
 159     private ScrollPaneAdjustable hAdjustable;
 160 
 161     private static final String base = "scrollpane";
 162     private static int nameCounter = 0;
 163 
 164     private static final boolean defaultWheelScroll = true;
 165 
 166     /**
 167      * Indicates whether or not scrolling should take place when a
 168      * MouseWheelEvent is received.
 169      *
 170      * @serial
 171      * @since 1.4
 172      */
 173     private boolean wheelScrollingEnabled = defaultWheelScroll;
 174 
 175     /*
 176      * JDK 1.1 serialVersionUID
 177      */
 178     private static final long serialVersionUID = 7956609840827222915L;
 179 
 180     /**
 181      * Create a new scrollpane container with a scrollbar display
 182      * policy of "as needed".
 183      * @throws HeadlessException if GraphicsEnvironment.isHeadless()
 184      *     returns true
 185      * @see java.awt.GraphicsEnvironment#isHeadless
 186      */
 187     public ScrollPane() throws HeadlessException {
 188         this(SCROLLBARS_AS_NEEDED);
 189     }
 190 
 191     /**
 192      * Create a new scrollpane container.
 193      * @param scrollbarDisplayPolicy policy for when scrollbars should be shown
 194      * @throws IllegalArgumentException if the specified scrollbar
 195      *     display policy is invalid
 196      * @throws HeadlessException if GraphicsEnvironment.isHeadless()
 197      *     returns true
 198      * @see java.awt.GraphicsEnvironment#isHeadless
 199      */
 200     @ConstructorProperties({"scrollbarDisplayPolicy"})
 201     public ScrollPane(int scrollbarDisplayPolicy) throws HeadlessException {
 202         GraphicsEnvironment.checkHeadless();
 203         this.layoutMgr = null;
 204         this.width = 100;
 205         this.height = 100;
 206         switch (scrollbarDisplayPolicy) {
 207             case SCROLLBARS_NEVER:
 208             case SCROLLBARS_AS_NEEDED:
 209             case SCROLLBARS_ALWAYS:
 210                 this.scrollbarDisplayPolicy = scrollbarDisplayPolicy;
 211                 break;
 212             default:
 213                 throw new IllegalArgumentException("illegal scrollbar display policy");
 214         }
 215 
 216         vAdjustable = new ScrollPaneAdjustable(this, new PeerFixer(this),
 217                                                Adjustable.VERTICAL);
 218         hAdjustable = new ScrollPaneAdjustable(this, new PeerFixer(this),
 219                                                Adjustable.HORIZONTAL);
 220         setWheelScrollingEnabled(defaultWheelScroll);
 221     }
 222 
 223     /**
 224      * Construct a name for this component.  Called by getName() when the
 225      * name is null.
 226      */
 227     String constructComponentName() {
 228         synchronized (ScrollPane.class) {
 229             return base + nameCounter++;
 230         }
 231     }
 232 
 233     // The scrollpane won't work with a windowless child... it assumes
 234     // it is moving a child window around so the windowless child is
 235     // wrapped with a window.
 236     private void addToPanel(Component comp, Object constraints, int index) {
 237         Panel child = new Panel();
 238         child.setLayout(new BorderLayout());
 239         child.add(comp);
 240         super.addImpl(child, constraints, index);
 241         validate();
 242     }
 243 
 244     /**
 245      * Adds the specified component to this scroll pane container.
 246      * If the scroll pane has an existing child component, that
 247      * component is removed and the new one is added.
 248      * @param comp the component to be added
 249      * @param constraints  not applicable
 250      * @param index position of child component (must be &lt;= 0)
 251      */
 252     protected final void addImpl(Component comp, Object constraints, int index) {
 253         synchronized (getTreeLock()) {
 254             if (getComponentCount() > 0) {
 255                 remove(0);
 256             }
 257             if (index > 0) {
 258                 throw new IllegalArgumentException("position greater than 0");
 259             }
 260 
 261             if (!SunToolkit.isLightweightOrUnknown(comp)) {
 262                 super.addImpl(comp, constraints, index);
 263             } else {
 264                 addToPanel(comp, constraints, index);
 265             }
 266         }
 267     }
 268 
 269     /**
 270      * Returns the display policy for the scrollbars.
 271      * @return the display policy for the scrollbars
 272      */
 273     public int getScrollbarDisplayPolicy() {
 274         return scrollbarDisplayPolicy;
 275     }
 276 
 277     /**
 278      * Returns the current size of the scroll pane's view port.
 279      * @return the size of the view port in pixels
 280      */
 281     public Dimension getViewportSize() {
 282         Insets i = getInsets();
 283         return new Dimension(width - i.right - i.left,
 284                              height - i.top - i.bottom);
 285     }
 286 
 287     /**
 288      * Returns the height that would be occupied by a horizontal
 289      * scrollbar, which is independent of whether it is currently
 290      * displayed by the scroll pane or not.
 291      * @return the height of a horizontal scrollbar in pixels
 292      */
 293     public int getHScrollbarHeight() {
 294         int h = 0;
 295         if (scrollbarDisplayPolicy != SCROLLBARS_NEVER) {
 296             ScrollPanePeer peer = (ScrollPanePeer)this.peer;
 297             if (peer != null) {
 298                 h = peer.getHScrollbarHeight();
 299             }
 300         }
 301         return h;
 302     }
 303 
 304     /**
 305      * Returns the width that would be occupied by a vertical
 306      * scrollbar, which is independent of whether it is currently
 307      * displayed by the scroll pane or not.
 308      * @return the width of a vertical scrollbar in pixels
 309      */
 310     public int getVScrollbarWidth() {
 311         int w = 0;
 312         if (scrollbarDisplayPolicy != SCROLLBARS_NEVER) {
 313             ScrollPanePeer peer = (ScrollPanePeer)this.peer;
 314             if (peer != null) {
 315                 w = peer.getVScrollbarWidth();
 316             }
 317         }
 318         return w;
 319     }
 320 
 321     /**
 322      * Returns the <code>ScrollPaneAdjustable</code> object which
 323      * represents the state of the vertical scrollbar.
 324      * The declared return type of this method is
 325      * <code>Adjustable</code> to maintain backward compatibility.
 326      *
 327      * @see java.awt.ScrollPaneAdjustable
 328      * @return the vertical scrollbar state
 329      */
 330     public Adjustable getVAdjustable() {
 331         return vAdjustable;
 332     }
 333 
 334     /**
 335      * Returns the <code>ScrollPaneAdjustable</code> object which
 336      * represents the state of the horizontal scrollbar.
 337      * The declared return type of this method is
 338      * <code>Adjustable</code> to maintain backward compatibility.
 339      *
 340      * @see java.awt.ScrollPaneAdjustable
 341      * @return the horizontal scrollbar state
 342      */
 343     public Adjustable getHAdjustable() {
 344         return hAdjustable;
 345     }
 346 
 347     /**
 348      * Scrolls to the specified position within the child component.
 349      * A call to this method is only valid if the scroll pane contains
 350      * a child.  Specifying a position outside of the legal scrolling bounds
 351      * of the child will scroll to the closest legal position.
 352      * Legal bounds are defined to be the rectangle:
 353      * x = 0, y = 0, width = (child width - view port width),
 354      * height = (child height - view port height).
 355      * This is a convenience method which interfaces with the Adjustable
 356      * objects which represent the state of the scrollbars.
 357      * @param x the x position to scroll to
 358      * @param y the y position to scroll to
 359      * @throws NullPointerException if the scrollpane does not contain
 360      *     a child
 361      */
 362     public void setScrollPosition(int x, int y) {
 363         synchronized (getTreeLock()) {
 364             if (getComponentCount()==0) {
 365                 throw new NullPointerException("child is null");
 366             }
 367             hAdjustable.setValue(x);
 368             vAdjustable.setValue(y);
 369         }
 370     }
 371 
 372     /**
 373      * Scrolls to the specified position within the child component.
 374      * A call to this method is only valid if the scroll pane contains
 375      * a child and the specified position is within legal scrolling bounds
 376      * of the child.  Specifying a position outside of the legal scrolling
 377      * bounds of the child will scroll to the closest legal position.
 378      * Legal bounds are defined to be the rectangle:
 379      * x = 0, y = 0, width = (child width - view port width),
 380      * height = (child height - view port height).
 381      * This is a convenience method which interfaces with the Adjustable
 382      * objects which represent the state of the scrollbars.
 383      * @param p the Point representing the position to scroll to
 384      * @throws NullPointerException if {@code p} is {@code null}
 385      */
 386     public void setScrollPosition(Point p) {
 387         setScrollPosition(p.x, p.y);
 388     }
 389 
 390     /**
 391      * Returns the current x,y position within the child which is displayed
 392      * at the 0,0 location of the scrolled panel's view port.
 393      * This is a convenience method which interfaces with the adjustable
 394      * objects which represent the state of the scrollbars.
 395      * @return the coordinate position for the current scroll position
 396      * @throws NullPointerException if the scrollpane does not contain
 397      *     a child
 398      */
 399     @Transient
 400     public Point getScrollPosition() {
 401         synchronized (getTreeLock()) {
 402             if (getComponentCount()==0) {
 403                 throw new NullPointerException("child is null");
 404             }
 405             return new Point(hAdjustable.getValue(), vAdjustable.getValue());
 406         }
 407     }
 408 
 409     /**
 410      * Sets the layout manager for this container.  This method is
 411      * overridden to prevent the layout mgr from being set.
 412      * @param mgr the specified layout manager
 413      */
 414     public final void setLayout(LayoutManager mgr) {
 415         throw new AWTError("ScrollPane controls layout");
 416     }
 417 
 418     /**
 419      * Lays out this container by resizing its child to its preferred size.
 420      * If the new preferred size of the child causes the current scroll
 421      * position to be invalid, the scroll position is set to the closest
 422      * valid position.
 423      *
 424      * @see Component#validate
 425      */
 426     public void doLayout() {
 427         layout();
 428     }
 429 
 430     /**
 431      * Determine the size to allocate the child component.
 432      * If the viewport area is bigger than the preferred size
 433      * of the child then the child is allocated enough
 434      * to fill the viewport, otherwise the child is given
 435      * it's preferred size.
 436      */
 437     Dimension calculateChildSize() {
 438         //
 439         // calculate the view size, accounting for border but not scrollbars
 440         // - don't use right/bottom insets since they vary depending
 441         //   on whether or not scrollbars were displayed on last resize
 442         //
 443         Dimension       size = getSize();
 444         Insets          insets = getInsets();
 445         int             viewWidth = size.width - insets.left*2;
 446         int             viewHeight = size.height - insets.top*2;
 447 
 448         //
 449         // determine whether or not horz or vert scrollbars will be displayed
 450         //
 451         boolean vbarOn;
 452         boolean hbarOn;
 453         Component child = getComponent(0);
 454         Dimension childSize = new Dimension(child.getPreferredSize());
 455 
 456         if (scrollbarDisplayPolicy == SCROLLBARS_AS_NEEDED) {
 457             vbarOn = childSize.height > viewHeight;
 458             hbarOn = childSize.width  > viewWidth;
 459         } else if (scrollbarDisplayPolicy == SCROLLBARS_ALWAYS) {
 460             vbarOn = hbarOn = true;
 461         } else { // SCROLLBARS_NEVER
 462             vbarOn = hbarOn = false;
 463         }
 464 
 465         //
 466         // adjust predicted view size to account for scrollbars
 467         //
 468         int vbarWidth = getVScrollbarWidth();
 469         int hbarHeight = getHScrollbarHeight();
 470         if (vbarOn) {
 471             viewWidth -= vbarWidth;
 472         }
 473         if(hbarOn) {
 474             viewHeight -= hbarHeight;
 475         }
 476 
 477         //
 478         // if child is smaller than view, size it up
 479         //
 480         if (childSize.width < viewWidth) {
 481             childSize.width = viewWidth;
 482         }
 483         if (childSize.height < viewHeight) {
 484             childSize.height = viewHeight;
 485         }
 486 
 487         return childSize;
 488     }
 489 
 490     /**
 491      * @deprecated As of JDK version 1.1,
 492      * replaced by <code>doLayout()</code>.
 493      */
 494     @Deprecated
 495     public void layout() {
 496         if (getComponentCount()==0) {
 497             return;
 498         }
 499         Component c = getComponent(0);
 500         Point p = getScrollPosition();
 501         Dimension cs = calculateChildSize();
 502         Dimension vs = getViewportSize();
 503         Insets i = getInsets();
 504 
 505         c.reshape(i.left - p.x, i.top - p.y, cs.width, cs.height);
 506         ScrollPanePeer peer = (ScrollPanePeer)this.peer;
 507         if (peer != null) {
 508             peer.childResized(cs.width, cs.height);
 509         }
 510 
 511         // update adjustables... the viewport size may have changed
 512         // with the scrollbars coming or going so the viewport size
 513         // is updated before the adjustables.
 514         vs = getViewportSize();
 515         hAdjustable.setSpan(0, cs.width, vs.width);
 516         vAdjustable.setSpan(0, cs.height, vs.height);
 517     }
 518 
 519     /**
 520      * Prints the component in this scroll pane.
 521      * @param g the specified Graphics window
 522      * @see Component#print
 523      * @see Component#printAll
 524      */
 525     public void printComponents(Graphics g) {
 526         if (getComponentCount()==0) {
 527             return;
 528         }
 529         Component c = getComponent(0);
 530         Point p = c.getLocation();
 531         Dimension vs = getViewportSize();
 532         Insets i = getInsets();
 533 
 534         Graphics cg = g.create();
 535         try {
 536             cg.clipRect(i.left, i.top, vs.width, vs.height);
 537             cg.translate(p.x, p.y);
 538             c.printAll(cg);
 539         } finally {
 540             cg.dispose();
 541         }
 542     }
 543 
 544     /**
 545      * Creates the scroll pane's peer.
 546      */
 547     public void addNotify() {
 548         synchronized (getTreeLock()) {
 549 
 550             int vAdjustableValue = 0;
 551             int hAdjustableValue = 0;
 552 
 553             // Bug 4124460. Save the current adjustable values,
 554             // so they can be restored after addnotify. Set the
 555             // adjustables to 0, to prevent crashes for possible
 556             // negative values.
 557             if (getComponentCount() > 0) {
 558                 vAdjustableValue = vAdjustable.getValue();
 559                 hAdjustableValue = hAdjustable.getValue();
 560                 vAdjustable.setValue(0);
 561                 hAdjustable.setValue(0);
 562             }
 563 
 564             if (peer == null)
 565                 peer = getToolkit().createScrollPane(this);
 566             super.addNotify();
 567 
 568             // Bug 4124460. Restore the adjustable values.
 569             if (getComponentCount() > 0) {
 570                 vAdjustable.setValue(vAdjustableValue);
 571                 hAdjustable.setValue(hAdjustableValue);
 572             }
 573         }
 574     }
 575 
 576     /**
 577      * Returns a string representing the state of this
 578      * <code>ScrollPane</code>. This
 579      * method is intended to be used only for debugging purposes, and the
 580      * content and format of the returned string may vary between
 581      * implementations. The returned string may be empty but may not be
 582      * <code>null</code>.
 583      *
 584      * @return the parameter string of this scroll pane
 585      */
 586     public String paramString() {
 587         String sdpStr;
 588         switch (scrollbarDisplayPolicy) {
 589             case SCROLLBARS_AS_NEEDED:
 590                 sdpStr = "as-needed";
 591                 break;
 592             case SCROLLBARS_ALWAYS:
 593                 sdpStr = "always";
 594                 break;
 595             case SCROLLBARS_NEVER:
 596                 sdpStr = "never";
 597                 break;
 598             default:
 599                 sdpStr = "invalid display policy";
 600         }
 601         Point p = (getComponentCount()>0)? getScrollPosition() : new Point(0,0);
 602         Insets i = getInsets();
 603         return super.paramString()+",ScrollPosition=("+p.x+","+p.y+")"+
 604             ",Insets=("+i.top+","+i.left+","+i.bottom+","+i.right+")"+
 605             ",ScrollbarDisplayPolicy="+sdpStr+
 606         ",wheelScrollingEnabled="+isWheelScrollingEnabled();
 607     }
 608 
 609     void autoProcessMouseWheel(MouseWheelEvent e) {
 610         processMouseWheelEvent(e);
 611     }
 612 
 613     /**
 614      * Process mouse wheel events that are delivered to this
 615      * <code>ScrollPane</code> by scrolling an appropriate amount.
 616      * <p>Note that if the event parameter is <code>null</code>
 617      * the behavior is unspecified and may result in an
 618      * exception.
 619      *
 620      * @param e  the mouse wheel event
 621      * @since 1.4
 622      */
 623     protected void processMouseWheelEvent(MouseWheelEvent e) {
 624         if (isWheelScrollingEnabled()) {
 625             ScrollPaneWheelScroller.handleWheelScrolling(this, e);
 626             e.consume();
 627         }
 628         super.processMouseWheelEvent(e);
 629     }
 630 
 631     /**
 632      * If wheel scrolling is enabled, we return true for MouseWheelEvents
 633      * @since 1.4
 634      */
 635     protected boolean eventTypeEnabled(int type) {
 636         if (type == MouseEvent.MOUSE_WHEEL && isWheelScrollingEnabled()) {
 637             return true;
 638         }
 639         else {
 640             return super.eventTypeEnabled(type);
 641         }
 642     }
 643 
 644     /**
 645      * Enables/disables scrolling in response to movement of the mouse wheel.
 646      * Wheel scrolling is enabled by default.
 647      *
 648      * @param handleWheel   <code>true</code> if scrolling should be done
 649      *                      automatically for a MouseWheelEvent,
 650      *                      <code>false</code> otherwise.
 651      * @see #isWheelScrollingEnabled
 652      * @see java.awt.event.MouseWheelEvent
 653      * @see java.awt.event.MouseWheelListener
 654      * @since 1.4
 655      */
 656     public void setWheelScrollingEnabled(boolean handleWheel) {
 657         wheelScrollingEnabled = handleWheel;
 658     }
 659 
 660     /**
 661      * Indicates whether or not scrolling will take place in response to
 662      * the mouse wheel.  Wheel scrolling is enabled by default.
 663      *
 664      * @return {@code true} if the wheel scrolling enabled;
 665      *         otherwise {@code false}
 666      *
 667      * @see #setWheelScrollingEnabled(boolean)
 668      * @since 1.4
 669      */
 670     public boolean isWheelScrollingEnabled() {
 671         return wheelScrollingEnabled;
 672     }
 673 
 674 
 675     /**
 676      * Writes default serializable fields to stream.
 677      */
 678     private void writeObject(ObjectOutputStream s) throws IOException {
 679         // 4352819: We only need this degenerate writeObject to make
 680         // it safe for future versions of this class to write optional
 681         // data to the stream.
 682         s.defaultWriteObject();
 683     }
 684 
 685     /**
 686      * Reads default serializable fields to stream.
 687      * @exception HeadlessException if
 688      * <code>GraphicsEnvironment.isHeadless()</code> returns
 689      * <code>true</code>
 690      * @see java.awt.GraphicsEnvironment#isHeadless
 691      */
 692     private void readObject(ObjectInputStream s)
 693         throws ClassNotFoundException, IOException, HeadlessException
 694     {
 695         GraphicsEnvironment.checkHeadless();
 696         // 4352819: Gotcha!  Cannot use s.defaultReadObject here and
 697         // then continue with reading optional data.  Use GetField instead.
 698         ObjectInputStream.GetField f = s.readFields();
 699 
 700         // Old fields
 701         scrollbarDisplayPolicy = f.get("scrollbarDisplayPolicy",
 702                                        SCROLLBARS_AS_NEEDED);
 703         hAdjustable = (ScrollPaneAdjustable)f.get("hAdjustable", null);
 704         vAdjustable = (ScrollPaneAdjustable)f.get("vAdjustable", null);
 705 
 706         // Since 1.4
 707         wheelScrollingEnabled = f.get("wheelScrollingEnabled",
 708                                       defaultWheelScroll);
 709 
 710 //      // Note to future maintainers
 711 //      if (f.defaulted("wheelScrollingEnabled")) {
 712 //          // We are reading pre-1.4 stream that doesn't have
 713 //          // optional data, not even the TC_ENDBLOCKDATA marker.
 714 //          // Reading anything after this point is unsafe as we will
 715 //          // read unrelated objects further down the stream (4352819).
 716 //      }
 717 //      else {
 718 //          // Reading data from 1.4 or later, it's ok to try to read
 719 //          // optional data as OptionalDataException with eof == true
 720 //          // will be correctly reported
 721 //      }
 722     }
 723 
 724     class PeerFixer implements AdjustmentListener, java.io.Serializable
 725     {
 726         private static final long serialVersionUID = 1043664721353696630L;
 727 
 728         PeerFixer(ScrollPane scroller) {
 729             this.scroller = scroller;
 730         }
 731 
 732         /**
 733          * Invoked when the value of the adjustable has changed.
 734          */
 735         @SuppressWarnings("deprecation")
 736         public void adjustmentValueChanged(AdjustmentEvent e) {
 737             Adjustable adj = e.getAdjustable();
 738             int value = e.getValue();
 739             ScrollPanePeer peer = (ScrollPanePeer) scroller.peer;
 740             if (peer != null) {
 741                 peer.setValue(adj, value);
 742             }
 743 
 744             Component c = scroller.getComponent(0);
 745             switch(adj.getOrientation()) {
 746             case Adjustable.VERTICAL:
 747                 c.move(c.getLocation().x, -(value));
 748                 break;
 749             case Adjustable.HORIZONTAL:
 750                 c.move(-(value), c.getLocation().y);
 751                 break;
 752             default:
 753                 throw new IllegalArgumentException("Illegal adjustable orientation");
 754             }
 755         }
 756 
 757         private ScrollPane scroller;
 758     }
 759 
 760 
 761 /////////////////
 762 // Accessibility support
 763 ////////////////
 764 
 765     /**
 766      * Gets the AccessibleContext associated with this ScrollPane.
 767      * For scroll panes, the AccessibleContext takes the form of an
 768      * AccessibleAWTScrollPane.
 769      * A new AccessibleAWTScrollPane instance is created if necessary.
 770      *
 771      * @return an AccessibleAWTScrollPane that serves as the
 772      *         AccessibleContext of this ScrollPane
 773      * @since 1.3
 774      */
 775     public AccessibleContext getAccessibleContext() {
 776         if (accessibleContext == null) {
 777             accessibleContext = new AccessibleAWTScrollPane();
 778         }
 779         return accessibleContext;
 780     }
 781 
 782     /**
 783      * This class implements accessibility support for the
 784      * <code>ScrollPane</code> class.  It provides an implementation of the
 785      * Java Accessibility API appropriate to scroll pane user-interface
 786      * elements.
 787      * @since 1.3
 788      */
 789     protected class AccessibleAWTScrollPane extends AccessibleAWTContainer
 790     {
 791         /*
 792          * JDK 1.3 serialVersionUID
 793          */
 794         private static final long serialVersionUID = 6100703663886637L;
 795 
 796         /**
 797          * Get the role of this object.
 798          *
 799          * @return an instance of AccessibleRole describing the role of the
 800          * object
 801          * @see AccessibleRole
 802          */
 803         public AccessibleRole getAccessibleRole() {
 804             return AccessibleRole.SCROLL_PANE;
 805         }
 806 
 807     } // class AccessibleAWTScrollPane
 808 
 809 }
 810 
 811 /*
 812  * In JDK 1.1.1, the pkg private class java.awt.PeerFixer was moved to
 813  * become an inner class of ScrollPane, which broke serialization
 814  * for ScrollPane objects using JDK 1.1.
 815  * Instead of moving it back out here, which would break all JDK 1.1.x
 816  * releases, we keep PeerFixer in both places. Because of the scoping rules,
 817  * the PeerFixer that is used in ScrollPane will be the one that is the
 818  * inner class. This pkg private PeerFixer class below will only be used
 819  * if the Java 2 platform is used to deserialize ScrollPane objects that were serialized
 820  * using JDK1.1
 821  */
 822 class PeerFixer implements AdjustmentListener, java.io.Serializable {
 823     /*
 824      * serialVersionUID
 825      */
 826     private static final long serialVersionUID = 7051237413532574756L;
 827 
 828     PeerFixer(ScrollPane scroller) {
 829         this.scroller = scroller;
 830     }
 831 
 832     /**
 833      * Invoked when the value of the adjustable has changed.
 834      */
 835     @SuppressWarnings("deprecation")
 836     public void adjustmentValueChanged(AdjustmentEvent e) {
 837         Adjustable adj = e.getAdjustable();
 838         int value = e.getValue();
 839         ScrollPanePeer peer = (ScrollPanePeer) scroller.peer;
 840         if (peer != null) {
 841             peer.setValue(adj, value);
 842         }
 843 
 844         Component c = scroller.getComponent(0);
 845         switch(adj.getOrientation()) {
 846         case Adjustable.VERTICAL:
 847             c.move(c.getLocation().x, -(value));
 848             break;
 849         case Adjustable.HORIZONTAL:
 850             c.move(-(value), c.getLocation().y);
 851             break;
 852         default:
 853             throw new IllegalArgumentException("Illegal adjustable orientation");
 854         }
 855     }
 856 
 857     private ScrollPane scroller;
 858 }