1 /*
2  * Copyright (c) 1996, 2013, 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      */
initIDs()98     private static native void initIDs();
99 
100     static {
101         /* ensure that the necessary native libraries are loaded */
Toolkit.loadLibraries()102         Toolkit.loadLibraries();
103         if (!GraphicsEnvironment.isHeadless()) {
initIDs()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      */
ScrollPane()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"})
ScrollPane(int 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      */
constructComponentName()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.
addToPanel(Component comp, Object constraints, int index)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      */
addImpl(Component comp, Object constraints, int index)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      */
getScrollbarDisplayPolicy()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      */
getViewportSize()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      */
getHScrollbarHeight()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      */
getVScrollbarWidth()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      * @see java.awt.ScrollPaneAdjustable
327      */
getVAdjustable()328     public Adjustable getVAdjustable() {
329         return vAdjustable;
330     }
331 
332     /**
333      * Returns the <code>ScrollPaneAdjustable</code> object which
334      * represents the state of the horizontal scrollbar.
335      * The declared return type of this method is
336      * <code>Adjustable</code> to maintain backward compatibility.
337      * @see java.awt.ScrollPaneAdjustable
338      */
getHAdjustable()339     public Adjustable getHAdjustable() {
340         return hAdjustable;
341     }
342 
343     /**
344      * Scrolls to the specified position within the child component.
345      * A call to this method is only valid if the scroll pane contains
346      * a child.  Specifying a position outside of the legal scrolling bounds
347      * of the child will scroll to the closest legal position.
348      * Legal bounds are defined to be the rectangle:
349      * x = 0, y = 0, width = (child width - view port width),
350      * height = (child height - view port height).
351      * This is a convenience method which interfaces with the Adjustable
352      * objects which represent the state of the scrollbars.
353      * @param x the x position to scroll to
354      * @param y the y position to scroll to
355      * @throws NullPointerException if the scrollpane does not contain
356      *     a child
357      */
setScrollPosition(int x, int y)358     public void setScrollPosition(int x, int y) {
359         synchronized (getTreeLock()) {
360             if (getComponentCount()==0) {
361                 throw new NullPointerException("child is null");
362             }
363             hAdjustable.setValue(x);
364             vAdjustable.setValue(y);
365         }
366     }
367 
368     /**
369      * Scrolls to the specified position within the child component.
370      * A call to this method is only valid if the scroll pane contains
371      * a child and the specified position is within legal scrolling bounds
372      * of the child.  Specifying a position outside of the legal scrolling
373      * bounds of the child will scroll to the closest legal position.
374      * Legal bounds are defined to be the rectangle:
375      * x = 0, y = 0, width = (child width - view port width),
376      * height = (child height - view port height).
377      * This is a convenience method which interfaces with the Adjustable
378      * objects which represent the state of the scrollbars.
379      * @param p the Point representing the position to scroll to
380      * @throws NullPointerException if {@code p} is {@code null}
381      */
setScrollPosition(Point p)382     public void setScrollPosition(Point p) {
383         setScrollPosition(p.x, p.y);
384     }
385 
386     /**
387      * Returns the current x,y position within the child which is displayed
388      * at the 0,0 location of the scrolled panel's view port.
389      * This is a convenience method which interfaces with the adjustable
390      * objects which represent the state of the scrollbars.
391      * @return the coordinate position for the current scroll position
392      * @throws NullPointerException if the scrollpane does not contain
393      *     a child
394      */
395     @Transient
getScrollPosition()396     public Point getScrollPosition() {
397         synchronized (getTreeLock()) {
398             if (getComponentCount()==0) {
399                 throw new NullPointerException("child is null");
400             }
401             return new Point(hAdjustable.getValue(), vAdjustable.getValue());
402         }
403     }
404 
405     /**
406      * Sets the layout manager for this container.  This method is
407      * overridden to prevent the layout mgr from being set.
408      * @param mgr the specified layout manager
409      */
setLayout(LayoutManager mgr)410     public final void setLayout(LayoutManager mgr) {
411         throw new AWTError("ScrollPane controls layout");
412     }
413 
414     /**
415      * Lays out this container by resizing its child to its preferred size.
416      * If the new preferred size of the child causes the current scroll
417      * position to be invalid, the scroll position is set to the closest
418      * valid position.
419      *
420      * @see Component#validate
421      */
doLayout()422     public void doLayout() {
423         layout();
424     }
425 
426     /**
427      * Determine the size to allocate the child component.
428      * If the viewport area is bigger than the preferred size
429      * of the child then the child is allocated enough
430      * to fill the viewport, otherwise the child is given
431      * it's preferred size.
432      */
calculateChildSize()433     Dimension calculateChildSize() {
434         //
435         // calculate the view size, accounting for border but not scrollbars
436         // - don't use right/bottom insets since they vary depending
437         //   on whether or not scrollbars were displayed on last resize
438         //
439         Dimension       size = getSize();
440         Insets          insets = getInsets();
441         int             viewWidth = size.width - insets.left*2;
442         int             viewHeight = size.height - insets.top*2;
443 
444         //
445         // determine whether or not horz or vert scrollbars will be displayed
446         //
447         boolean vbarOn;
448         boolean hbarOn;
449         Component child = getComponent(0);
450         Dimension childSize = new Dimension(child.getPreferredSize());
451 
452         if (scrollbarDisplayPolicy == SCROLLBARS_AS_NEEDED) {
453             vbarOn = childSize.height > viewHeight;
454             hbarOn = childSize.width  > viewWidth;
455         } else if (scrollbarDisplayPolicy == SCROLLBARS_ALWAYS) {
456             vbarOn = hbarOn = true;
457         } else { // SCROLLBARS_NEVER
458             vbarOn = hbarOn = false;
459         }
460 
461         //
462         // adjust predicted view size to account for scrollbars
463         //
464         int vbarWidth = getVScrollbarWidth();
465         int hbarHeight = getHScrollbarHeight();
466         if (vbarOn) {
467             viewWidth -= vbarWidth;
468         }
469         if(hbarOn) {
470             viewHeight -= hbarHeight;
471         }
472 
473         //
474         // if child is smaller than view, size it up
475         //
476         if (childSize.width < viewWidth) {
477             childSize.width = viewWidth;
478         }
479         if (childSize.height < viewHeight) {
480             childSize.height = viewHeight;
481         }
482 
483         return childSize;
484     }
485 
486     /**
487      * @deprecated As of JDK version 1.1,
488      * replaced by <code>doLayout()</code>.
489      */
490     @Deprecated
layout()491     public void layout() {
492         if (getComponentCount()==0) {
493             return;
494         }
495         Component c = getComponent(0);
496         Point p = getScrollPosition();
497         Dimension cs = calculateChildSize();
498         Dimension vs = getViewportSize();
499 
500         c.reshape(- p.x, - p.y, cs.width, cs.height);
501         ScrollPanePeer peer = (ScrollPanePeer)this.peer;
502         if (peer != null) {
503             peer.childResized(cs.width, cs.height);
504         }
505 
506         // update adjustables... the viewport size may have changed
507         // with the scrollbars coming or going so the viewport size
508         // is updated before the adjustables.
509         vs = getViewportSize();
510         hAdjustable.setSpan(0, cs.width, vs.width);
511         vAdjustable.setSpan(0, cs.height, vs.height);
512     }
513 
514     /**
515      * Prints the component in this scroll pane.
516      * @param g the specified Graphics window
517      * @see Component#print
518      * @see Component#printAll
519      */
printComponents(Graphics g)520     public void printComponents(Graphics g) {
521         if (getComponentCount()==0) {
522             return;
523         }
524         Component c = getComponent(0);
525         Point p = c.getLocation();
526         Dimension vs = getViewportSize();
527         Insets i = getInsets();
528 
529         Graphics cg = g.create();
530         try {
531             cg.clipRect(i.left, i.top, vs.width, vs.height);
532             cg.translate(p.x, p.y);
533             c.printAll(cg);
534         } finally {
535             cg.dispose();
536         }
537     }
538 
539     /**
540      * Creates the scroll pane's peer.
541      */
addNotify()542     public void addNotify() {
543         synchronized (getTreeLock()) {
544 
545             int vAdjustableValue = 0;
546             int hAdjustableValue = 0;
547 
548             // Bug 4124460. Save the current adjustable values,
549             // so they can be restored after addnotify. Set the
550             // adjustables to 0, to prevent crashes for possible
551             // negative values.
552             if (getComponentCount() > 0) {
553                 vAdjustableValue = vAdjustable.getValue();
554                 hAdjustableValue = hAdjustable.getValue();
555                 vAdjustable.setValue(0);
556                 hAdjustable.setValue(0);
557             }
558 
559             if (peer == null)
560                 peer = getToolkit().createScrollPane(this);
561             super.addNotify();
562 
563             // Bug 4124460. Restore the adjustable values.
564             if (getComponentCount() > 0) {
565                 vAdjustable.setValue(vAdjustableValue);
566                 hAdjustable.setValue(hAdjustableValue);
567             }
568         }
569     }
570 
571     /**
572      * Returns a string representing the state of this
573      * <code>ScrollPane</code>. This
574      * method is intended to be used only for debugging purposes, and the
575      * content and format of the returned string may vary between
576      * implementations. The returned string may be empty but may not be
577      * <code>null</code>.
578      *
579      * @return the parameter string of this scroll pane
580      */
paramString()581     public String paramString() {
582         String sdpStr;
583         switch (scrollbarDisplayPolicy) {
584             case SCROLLBARS_AS_NEEDED:
585                 sdpStr = "as-needed";
586                 break;
587             case SCROLLBARS_ALWAYS:
588                 sdpStr = "always";
589                 break;
590             case SCROLLBARS_NEVER:
591                 sdpStr = "never";
592                 break;
593             default:
594                 sdpStr = "invalid display policy";
595         }
596         Point p = (getComponentCount()>0)? getScrollPosition() : new Point(0,0);
597         Insets i = getInsets();
598         return super.paramString()+",ScrollPosition=("+p.x+","+p.y+")"+
599             ",Insets=("+i.top+","+i.left+","+i.bottom+","+i.right+")"+
600             ",ScrollbarDisplayPolicy="+sdpStr+
601         ",wheelScrollingEnabled="+isWheelScrollingEnabled();
602     }
603 
autoProcessMouseWheel(MouseWheelEvent e)604     void autoProcessMouseWheel(MouseWheelEvent e) {
605         processMouseWheelEvent(e);
606     }
607 
608     /**
609      * Process mouse wheel events that are delivered to this
610      * <code>ScrollPane</code> by scrolling an appropriate amount.
611      * <p>Note that if the event parameter is <code>null</code>
612      * the behavior is unspecified and may result in an
613      * exception.
614      *
615      * @param e  the mouse wheel event
616      * @since 1.4
617      */
processMouseWheelEvent(MouseWheelEvent e)618     protected void processMouseWheelEvent(MouseWheelEvent e) {
619         if (isWheelScrollingEnabled()) {
620             ScrollPaneWheelScroller.handleWheelScrolling(this, e);
621             e.consume();
622         }
623         super.processMouseWheelEvent(e);
624     }
625 
626     /**
627      * If wheel scrolling is enabled, we return true for MouseWheelEvents
628      * @since 1.4
629      */
eventTypeEnabled(int type)630     protected boolean eventTypeEnabled(int type) {
631         if (type == MouseEvent.MOUSE_WHEEL && isWheelScrollingEnabled()) {
632             return true;
633         }
634         else {
635             return super.eventTypeEnabled(type);
636         }
637     }
638 
639     /**
640      * Enables/disables scrolling in response to movement of the mouse wheel.
641      * Wheel scrolling is enabled by default.
642      *
643      * @param handleWheel   <code>true</code> if scrolling should be done
644      *                      automatically for a MouseWheelEvent,
645      *                      <code>false</code> otherwise.
646      * @see #isWheelScrollingEnabled
647      * @see java.awt.event.MouseWheelEvent
648      * @see java.awt.event.MouseWheelListener
649      * @since 1.4
650      */
setWheelScrollingEnabled(boolean handleWheel)651     public void setWheelScrollingEnabled(boolean handleWheel) {
652         wheelScrollingEnabled = handleWheel;
653     }
654 
655     /**
656      * Indicates whether or not scrolling will take place in response to
657      * the mouse wheel.  Wheel scrolling is enabled by default.
658      *
659      * @see #setWheelScrollingEnabled(boolean)
660      * @since 1.4
661      */
isWheelScrollingEnabled()662     public boolean isWheelScrollingEnabled() {
663         return wheelScrollingEnabled;
664     }
665 
666 
667     /**
668      * Writes default serializable fields to stream.
669      */
writeObject(ObjectOutputStream s)670     private void writeObject(ObjectOutputStream s) throws IOException {
671         // 4352819: We only need this degenerate writeObject to make
672         // it safe for future versions of this class to write optional
673         // data to the stream.
674         s.defaultWriteObject();
675     }
676 
677     /**
678      * Reads default serializable fields to stream.
679      * @exception HeadlessException if
680      * <code>GraphicsEnvironment.isHeadless()</code> returns
681      * <code>true</code>
682      * @see java.awt.GraphicsEnvironment#isHeadless
683      */
readObject(ObjectInputStream s)684     private void readObject(ObjectInputStream s)
685         throws ClassNotFoundException, IOException, HeadlessException
686     {
687         GraphicsEnvironment.checkHeadless();
688         // 4352819: Gotcha!  Cannot use s.defaultReadObject here and
689         // then continue with reading optional data.  Use GetField instead.
690         ObjectInputStream.GetField f = s.readFields();
691 
692         // Old fields
693         scrollbarDisplayPolicy = f.get("scrollbarDisplayPolicy",
694                                        SCROLLBARS_AS_NEEDED);
695         hAdjustable = (ScrollPaneAdjustable)f.get("hAdjustable", null);
696         vAdjustable = (ScrollPaneAdjustable)f.get("vAdjustable", null);
697 
698         // Since 1.4
699         wheelScrollingEnabled = f.get("wheelScrollingEnabled",
700                                       defaultWheelScroll);
701 
702 //      // Note to future maintainers
703 //      if (f.defaulted("wheelScrollingEnabled")) {
704 //          // We are reading pre-1.4 stream that doesn't have
705 //          // optional data, not even the TC_ENDBLOCKDATA marker.
706 //          // Reading anything after this point is unsafe as we will
707 //          // read unrelated objects further down the stream (4352819).
708 //      }
709 //      else {
710 //          // Reading data from 1.4 or later, it's ok to try to read
711 //          // optional data as OptionalDataException with eof == true
712 //          // will be correctly reported
713 //      }
714     }
715 
716     class PeerFixer implements AdjustmentListener, java.io.Serializable
717     {
718         private static final long serialVersionUID = 1043664721353696630L;
719 
PeerFixer(ScrollPane scroller)720         PeerFixer(ScrollPane scroller) {
721             this.scroller = scroller;
722         }
723 
724         /**
725          * Invoked when the value of the adjustable has changed.
726          */
adjustmentValueChanged(AdjustmentEvent e)727         public void adjustmentValueChanged(AdjustmentEvent e) {
728             Adjustable adj = e.getAdjustable();
729             int value = e.getValue();
730             ScrollPanePeer peer = (ScrollPanePeer) scroller.peer;
731             if (peer != null) {
732                 peer.setValue(adj, value);
733             }
734 
735             Component c = scroller.getComponent(0);
736             switch(adj.getOrientation()) {
737             case Adjustable.VERTICAL:
738                 c.move(c.getLocation().x, -(value));
739                 break;
740             case Adjustable.HORIZONTAL:
741                 c.move(-(value), c.getLocation().y);
742                 break;
743             default:
744                 throw new IllegalArgumentException("Illegal adjustable orientation");
745             }
746         }
747 
748         private ScrollPane scroller;
749     }
750 
751 
752 /////////////////
753 // Accessibility support
754 ////////////////
755 
756     /**
757      * Gets the AccessibleContext associated with this ScrollPane.
758      * For scroll panes, the AccessibleContext takes the form of an
759      * AccessibleAWTScrollPane.
760      * A new AccessibleAWTScrollPane instance is created if necessary.
761      *
762      * @return an AccessibleAWTScrollPane that serves as the
763      *         AccessibleContext of this ScrollPane
764      * @since 1.3
765      */
getAccessibleContext()766     public AccessibleContext getAccessibleContext() {
767         if (accessibleContext == null) {
768             accessibleContext = new AccessibleAWTScrollPane();
769         }
770         return accessibleContext;
771     }
772 
773     /**
774      * This class implements accessibility support for the
775      * <code>ScrollPane</code> class.  It provides an implementation of the
776      * Java Accessibility API appropriate to scroll pane user-interface
777      * elements.
778      * @since 1.3
779      */
780     protected class AccessibleAWTScrollPane extends AccessibleAWTContainer
781     {
782         /*
783          * JDK 1.3 serialVersionUID
784          */
785         private static final long serialVersionUID = 6100703663886637L;
786 
787         /**
788          * Get the role of this object.
789          *
790          * @return an instance of AccessibleRole describing the role of the
791          * object
792          * @see AccessibleRole
793          */
getAccessibleRole()794         public AccessibleRole getAccessibleRole() {
795             return AccessibleRole.SCROLL_PANE;
796         }
797 
798     } // class AccessibleAWTScrollPane
799 
800 }
801 
802 /*
803  * In JDK 1.1.1, the pkg private class java.awt.PeerFixer was moved to
804  * become an inner class of ScrollPane, which broke serialization
805  * for ScrollPane objects using JDK 1.1.
806  * Instead of moving it back out here, which would break all JDK 1.1.x
807  * releases, we keep PeerFixer in both places. Because of the scoping rules,
808  * the PeerFixer that is used in ScrollPane will be the one that is the
809  * inner class. This pkg private PeerFixer class below will only be used
810  * if the Java 2 platform is used to deserialize ScrollPane objects that were serialized
811  * using JDK1.1
812  */
813 class PeerFixer implements AdjustmentListener, java.io.Serializable {
814     /*
815      * serialVersionUID
816      */
817     private static final long serialVersionUID = 7051237413532574756L;
818 
PeerFixer(ScrollPane scroller)819     PeerFixer(ScrollPane scroller) {
820         this.scroller = scroller;
821     }
822 
823     /**
824      * Invoked when the value of the adjustable has changed.
825      */
adjustmentValueChanged(AdjustmentEvent e)826     public void adjustmentValueChanged(AdjustmentEvent e) {
827         Adjustable adj = e.getAdjustable();
828         int value = e.getValue();
829         ScrollPanePeer peer = (ScrollPanePeer) scroller.peer;
830         if (peer != null) {
831             peer.setValue(adj, value);
832         }
833 
834         Component c = scroller.getComponent(0);
835         switch(adj.getOrientation()) {
836         case Adjustable.VERTICAL:
837             c.move(c.getLocation().x, -(value));
838             break;
839         case Adjustable.HORIZONTAL:
840             c.move(-(value), c.getLocation().y);
841             break;
842         default:
843             throw new IllegalArgumentException("Illegal adjustable orientation");
844         }
845     }
846 
847     private ScrollPane scroller;
848 }
849