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} objects (one for each
51  * dimension) which implement the {@code Adjustable} 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}.
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      */
initIDs()97     private static native void initIDs();
98 
99     static {
100         /* ensure that the necessary native libraries are loaded */
Toolkit.loadLibraries()101         Toolkit.loadLibraries();
102         if (!GraphicsEnvironment.isHeadless()) {
initIDs()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} methods, namely:
140      * {@code setMinimum()}, {@code setMaximum()},
141      * {@code setVisibleAmount()}.
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} methods, namely:
152      * {@code setMinimum()}, {@code setMaximum()},
153      * {@code setVisibleAmount()}.
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      */
ScrollPane()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"})
ScrollPane(int 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      */
constructComponentName()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.
addToPanel(Component comp, Object constraints, int index)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      */
addImpl(Component comp, Object constraints, int index)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      */
getScrollbarDisplayPolicy()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      */
getViewportSize()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      */
getHScrollbarHeight()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      */
getVScrollbarWidth()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} object which
322      * represents the state of the vertical scrollbar.
323      * The declared return type of this method is
324      * {@code Adjustable} to maintain backward compatibility.
325      *
326      * @see java.awt.ScrollPaneAdjustable
327      * @return the vertical scrollbar state
328      */
getVAdjustable()329     public Adjustable getVAdjustable() {
330         return vAdjustable;
331     }
332 
333     /**
334      * Returns the {@code ScrollPaneAdjustable} object which
335      * represents the state of the horizontal scrollbar.
336      * The declared return type of this method is
337      * {@code Adjustable} to maintain backward compatibility.
338      *
339      * @see java.awt.ScrollPaneAdjustable
340      * @return the horizontal scrollbar state
341      */
getHAdjustable()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      */
setScrollPosition(int x, int y)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      */
setScrollPosition(Point p)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
getScrollPosition()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      */
setLayout(LayoutManager mgr)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      */
doLayout()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      */
calculateChildSize()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()}.
492      */
493     @Deprecated
layout()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 
503         c.reshape(- p.x, - p.y, cs.width, cs.height);
504         ScrollPanePeer peer = (ScrollPanePeer)this.peer;
505         if (peer != null) {
506             peer.childResized(cs.width, cs.height);
507         }
508 
509         // update adjustables... the viewport size may have changed
510         // with the scrollbars coming or going so the viewport size
511         // is updated before the adjustables.
512         vs = getViewportSize();
513         hAdjustable.setSpan(0, cs.width, vs.width);
514         vAdjustable.setSpan(0, cs.height, vs.height);
515     }
516 
517     /**
518      * Prints the component in this scroll pane.
519      * @param g the specified Graphics window
520      * @see Component#print
521      * @see Component#printAll
522      */
printComponents(Graphics g)523     public void printComponents(Graphics g) {
524         if (getComponentCount()==0) {
525             return;
526         }
527         Component c = getComponent(0);
528         Point p = c.getLocation();
529         Dimension vs = getViewportSize();
530         Insets i = getInsets();
531 
532         Graphics cg = g.create();
533         try {
534             cg.clipRect(i.left, i.top, vs.width, vs.height);
535             cg.translate(p.x, p.y);
536             c.printAll(cg);
537         } finally {
538             cg.dispose();
539         }
540     }
541 
542     /**
543      * Creates the scroll pane's peer.
544      */
addNotify()545     public void addNotify() {
546         synchronized (getTreeLock()) {
547 
548             int vAdjustableValue = 0;
549             int hAdjustableValue = 0;
550 
551             // Bug 4124460. Save the current adjustable values,
552             // so they can be restored after addnotify. Set the
553             // adjustables to 0, to prevent crashes for possible
554             // negative values.
555             if (getComponentCount() > 0) {
556                 vAdjustableValue = vAdjustable.getValue();
557                 hAdjustableValue = hAdjustable.getValue();
558                 vAdjustable.setValue(0);
559                 hAdjustable.setValue(0);
560             }
561 
562             if (peer == null)
563                 peer = getComponentFactory().createScrollPane(this);
564             super.addNotify();
565 
566             // Bug 4124460. Restore the adjustable values.
567             if (getComponentCount() > 0) {
568                 vAdjustable.setValue(vAdjustableValue);
569                 hAdjustable.setValue(hAdjustableValue);
570             }
571         }
572     }
573 
574     /**
575      * Returns a string representing the state of this
576      * {@code ScrollPane}. This
577      * method is intended to be used only for debugging purposes, and the
578      * content and format of the returned string may vary between
579      * implementations. The returned string may be empty but may not be
580      * {@code null}.
581      *
582      * @return the parameter string of this scroll pane
583      */
paramString()584     public String paramString() {
585         String sdpStr;
586         switch (scrollbarDisplayPolicy) {
587             case SCROLLBARS_AS_NEEDED:
588                 sdpStr = "as-needed";
589                 break;
590             case SCROLLBARS_ALWAYS:
591                 sdpStr = "always";
592                 break;
593             case SCROLLBARS_NEVER:
594                 sdpStr = "never";
595                 break;
596             default:
597                 sdpStr = "invalid display policy";
598         }
599         Point p = (getComponentCount()>0)? getScrollPosition() : new Point(0,0);
600         Insets i = getInsets();
601         return super.paramString()+",ScrollPosition=("+p.x+","+p.y+")"+
602             ",Insets=("+i.top+","+i.left+","+i.bottom+","+i.right+")"+
603             ",ScrollbarDisplayPolicy="+sdpStr+
604         ",wheelScrollingEnabled="+isWheelScrollingEnabled();
605     }
606 
autoProcessMouseWheel(MouseWheelEvent e)607     void autoProcessMouseWheel(MouseWheelEvent e) {
608         processMouseWheelEvent(e);
609     }
610 
611     /**
612      * Process mouse wheel events that are delivered to this
613      * {@code ScrollPane} by scrolling an appropriate amount.
614      * <p>Note that if the event parameter is {@code null}
615      * the behavior is unspecified and may result in an
616      * exception.
617      *
618      * @param e  the mouse wheel event
619      * @since 1.4
620      */
processMouseWheelEvent(MouseWheelEvent e)621     protected void processMouseWheelEvent(MouseWheelEvent e) {
622         if (isWheelScrollingEnabled()) {
623             ScrollPaneWheelScroller.handleWheelScrolling(this, e);
624             e.consume();
625         }
626         super.processMouseWheelEvent(e);
627     }
628 
629     /**
630      * If wheel scrolling is enabled, we return true for MouseWheelEvents
631      * @since 1.4
632      */
eventTypeEnabled(int type)633     protected boolean eventTypeEnabled(int type) {
634         if (type == MouseEvent.MOUSE_WHEEL && isWheelScrollingEnabled()) {
635             return true;
636         }
637         else {
638             return super.eventTypeEnabled(type);
639         }
640     }
641 
642     /**
643      * Enables/disables scrolling in response to movement of the mouse wheel.
644      * Wheel scrolling is enabled by default.
645      *
646      * @param handleWheel   {@code true} if scrolling should be done
647      *                      automatically for a MouseWheelEvent,
648      *                      {@code false} otherwise.
649      * @see #isWheelScrollingEnabled
650      * @see java.awt.event.MouseWheelEvent
651      * @see java.awt.event.MouseWheelListener
652      * @since 1.4
653      */
setWheelScrollingEnabled(boolean handleWheel)654     public void setWheelScrollingEnabled(boolean handleWheel) {
655         wheelScrollingEnabled = handleWheel;
656     }
657 
658     /**
659      * Indicates whether or not scrolling will take place in response to
660      * the mouse wheel.  Wheel scrolling is enabled by default.
661      *
662      * @return {@code true} if the wheel scrolling enabled;
663      *         otherwise {@code false}
664      *
665      * @see #setWheelScrollingEnabled(boolean)
666      * @since 1.4
667      */
isWheelScrollingEnabled()668     public boolean isWheelScrollingEnabled() {
669         return wheelScrollingEnabled;
670     }
671 
672 
673     /**
674      * Writes default serializable fields to stream.
675      */
writeObject(ObjectOutputStream s)676     private void writeObject(ObjectOutputStream s) throws IOException {
677         // 4352819: We only need this degenerate writeObject to make
678         // it safe for future versions of this class to write optional
679         // data to the stream.
680         s.defaultWriteObject();
681     }
682 
683     /**
684      * Reads default serializable fields to stream.
685      * @exception HeadlessException if
686      * {@code GraphicsEnvironment.isHeadless()} returns
687      * {@code true}
688      * @see java.awt.GraphicsEnvironment#isHeadless
689      */
readObject(ObjectInputStream s)690     private void readObject(ObjectInputStream s)
691         throws ClassNotFoundException, IOException, HeadlessException
692     {
693         GraphicsEnvironment.checkHeadless();
694         // 4352819: Gotcha!  Cannot use s.defaultReadObject here and
695         // then continue with reading optional data.  Use GetField instead.
696         ObjectInputStream.GetField f = s.readFields();
697 
698         // Old fields
699         scrollbarDisplayPolicy = f.get("scrollbarDisplayPolicy",
700                                        SCROLLBARS_AS_NEEDED);
701         hAdjustable = (ScrollPaneAdjustable)f.get("hAdjustable", null);
702         vAdjustable = (ScrollPaneAdjustable)f.get("vAdjustable", null);
703 
704         // Since 1.4
705         wheelScrollingEnabled = f.get("wheelScrollingEnabled",
706                                       defaultWheelScroll);
707 
708 //      // Note to future maintainers
709 //      if (f.defaulted("wheelScrollingEnabled")) {
710 //          // We are reading pre-1.4 stream that doesn't have
711 //          // optional data, not even the TC_ENDBLOCKDATA marker.
712 //          // Reading anything after this point is unsafe as we will
713 //          // read unrelated objects further down the stream (4352819).
714 //      }
715 //      else {
716 //          // Reading data from 1.4 or later, it's ok to try to read
717 //          // optional data as OptionalDataException with eof == true
718 //          // will be correctly reported
719 //      }
720     }
721 
722     class PeerFixer implements AdjustmentListener, java.io.Serializable
723     {
724         private static final long serialVersionUID = 1043664721353696630L;
725 
PeerFixer(ScrollPane scroller)726         PeerFixer(ScrollPane scroller) {
727             this.scroller = scroller;
728         }
729 
730         /**
731          * Invoked when the value of the adjustable has changed.
732          */
733         @SuppressWarnings("deprecation")
adjustmentValueChanged(AdjustmentEvent e)734         public void adjustmentValueChanged(AdjustmentEvent e) {
735             Adjustable adj = e.getAdjustable();
736             int value = e.getValue();
737             ScrollPanePeer peer = (ScrollPanePeer) scroller.peer;
738             if (peer != null) {
739                 peer.setValue(adj, value);
740             }
741 
742             Component c = scroller.getComponent(0);
743             switch(adj.getOrientation()) {
744             case Adjustable.VERTICAL:
745                 c.move(c.getLocation().x, -(value));
746                 break;
747             case Adjustable.HORIZONTAL:
748                 c.move(-(value), c.getLocation().y);
749                 break;
750             default:
751                 throw new IllegalArgumentException("Illegal adjustable orientation");
752             }
753         }
754 
755         private ScrollPane scroller;
756     }
757 
758 
759 /////////////////
760 // Accessibility support
761 ////////////////
762 
763     /**
764      * Gets the AccessibleContext associated with this ScrollPane.
765      * For scroll panes, the AccessibleContext takes the form of an
766      * AccessibleAWTScrollPane.
767      * A new AccessibleAWTScrollPane instance is created if necessary.
768      *
769      * @return an AccessibleAWTScrollPane that serves as the
770      *         AccessibleContext of this ScrollPane
771      * @since 1.3
772      */
getAccessibleContext()773     public AccessibleContext getAccessibleContext() {
774         if (accessibleContext == null) {
775             accessibleContext = new AccessibleAWTScrollPane();
776         }
777         return accessibleContext;
778     }
779 
780     /**
781      * This class implements accessibility support for the
782      * {@code ScrollPane} class.  It provides an implementation of the
783      * Java Accessibility API appropriate to scroll pane user-interface
784      * elements.
785      * @since 1.3
786      */
787     protected class AccessibleAWTScrollPane extends AccessibleAWTContainer
788     {
789         /*
790          * JDK 1.3 serialVersionUID
791          */
792         private static final long serialVersionUID = 6100703663886637L;
793 
794         /**
795          * Get the role of this object.
796          *
797          * @return an instance of AccessibleRole describing the role of the
798          * object
799          * @see AccessibleRole
800          */
getAccessibleRole()801         public AccessibleRole getAccessibleRole() {
802             return AccessibleRole.SCROLL_PANE;
803         }
804 
805     } // class AccessibleAWTScrollPane
806 
807 }
808 
809 /*
810  * In JDK 1.1.1, the pkg private class java.awt.PeerFixer was moved to
811  * become an inner class of ScrollPane, which broke serialization
812  * for ScrollPane objects using JDK 1.1.
813  * Instead of moving it back out here, which would break all JDK 1.1.x
814  * releases, we keep PeerFixer in both places. Because of the scoping rules,
815  * the PeerFixer that is used in ScrollPane will be the one that is the
816  * inner class. This pkg private PeerFixer class below will only be used
817  * if the Java 2 platform is used to deserialize ScrollPane objects that were serialized
818  * using JDK1.1
819  */
820 class PeerFixer implements AdjustmentListener, java.io.Serializable {
821     /*
822      * serialVersionUID
823      */
824     private static final long serialVersionUID = 7051237413532574756L;
825 
PeerFixer(ScrollPane scroller)826     PeerFixer(ScrollPane scroller) {
827         this.scroller = scroller;
828     }
829 
830     /**
831      * Invoked when the value of the adjustable has changed.
832      */
833     @SuppressWarnings("deprecation")
adjustmentValueChanged(AdjustmentEvent e)834     public void adjustmentValueChanged(AdjustmentEvent e) {
835         Adjustable adj = e.getAdjustable();
836         int value = e.getValue();
837         ScrollPanePeer peer = (ScrollPanePeer) scroller.peer;
838         if (peer != null) {
839             peer.setValue(adj, value);
840         }
841 
842         Component c = scroller.getComponent(0);
843         switch(adj.getOrientation()) {
844         case Adjustable.VERTICAL:
845             c.move(c.getLocation().x, -(value));
846             break;
847         case Adjustable.HORIZONTAL:
848             c.move(-(value), c.getLocation().y);
849             break;
850         default:
851             throw new IllegalArgumentException("Illegal adjustable orientation");
852         }
853     }
854 
855     private ScrollPane scroller;
856 }
857