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