ScrollPane.java revision 12194:4a9eff2768ce
1246853Sdes/*
2246853Sdes * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
3246853Sdes * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4246853Sdes *
5246853Sdes * This code is free software; you can redistribute it and/or modify it
6246853Sdes * under the terms of the GNU General Public License version 2 only, as
7246853Sdes * published by the Free Software Foundation.  Oracle designates this
8246853Sdes * particular file as subject to the "Classpath" exception as provided
9246853Sdes * by Oracle in the LICENSE file that accompanied this code.
10246853Sdes *
11246853Sdes * This code is distributed in the hope that it will be useful, but WITHOUT
12246853Sdes * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13246853Sdes * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14246853Sdes * version 2 for more details (a copy is included in the LICENSE file that
15246853Sdes * accompanied this code).
16246853Sdes *
17246853Sdes * You should have received a copy of the GNU General Public License version
18246853Sdes * 2 along with this work; if not, write to the Free Software Foundation,
19246853Sdes * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20246853Sdes *
21246853Sdes * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22246853Sdes * or visit www.oracle.com if you need additional information or have any
23246853Sdes * questions.
24246853Sdes */
25246853Sdespackage java.awt;
26246853Sdes
27246853Sdesimport java.awt.peer.ScrollPanePeer;
28246853Sdesimport java.awt.event.*;
29246853Sdesimport javax.accessibility.*;
30246854Sdesimport sun.awt.ScrollPaneWheelScroller;
31246854Sdesimport sun.awt.SunToolkit;
32246853Sdes
33246853Sdesimport java.beans.ConstructorProperties;
34246853Sdesimport java.beans.Transient;
35246853Sdesimport java.io.ObjectInputStream;
36246853Sdesimport java.io.ObjectOutputStream;
37246853Sdesimport java.io.IOException;
38246853Sdes
39246853Sdes/**
40246853Sdes * A container class which implements automatic horizontal and/or
41246853Sdes * vertical scrolling for a single child component.  The display
42246853Sdes * policy for the scrollbars can be set to:
43246853Sdes * <OL>
44246853Sdes * <LI>as needed: scrollbars created and shown only when needed by scrollpane
45246853Sdes * <LI>always: scrollbars created and always shown by the scrollpane
46246853Sdes * <LI>never: scrollbars never created or shown by the scrollpane
47246853Sdes * </OL>
48246853Sdes * <P>
49246853Sdes * The state of the horizontal and vertical scrollbars is represented
50246853Sdes * by two <code>ScrollPaneAdjustable</code> objects (one for each
51246853Sdes * dimension) which implement the <code>Adjustable</code> interface.
52246853Sdes * The API provides methods to access those objects such that the
53246853Sdes * attributes on the Adjustable object (such as unitIncrement, value,
54246853Sdes * etc.) can be manipulated.
55246853Sdes * <P>
56246853Sdes * Certain adjustable properties (minimum, maximum, blockIncrement,
57246853Sdes * and visibleAmount) are set internally by the scrollpane in accordance
58246853Sdes * with the geometry of the scrollpane and its child and these should
59246853Sdes * not be set by programs using the scrollpane.
60246853Sdes * <P>
61246853Sdes * If the scrollbar display policy is defined as "never", then the
62246853Sdes * scrollpane can still be programmatically scrolled using the
63246853Sdes * setScrollPosition() method and the scrollpane will move and clip
64246853Sdes * the child's contents appropriately.  This policy is useful if the
65246853Sdes * program needs to create and manage its own adjustable controls.
66246853Sdes * <P>
67246853Sdes * The placement of the scrollbars is controlled by platform-specific
68246853Sdes * properties set by the user outside of the program.
69246853Sdes * <P>
70246853Sdes * The initial size of this container is set to 100x100, but can
71246853Sdes * be reset using setSize().
72246853Sdes * <P>
73246853Sdes * Scrolling with the wheel on a wheel-equipped mouse is enabled by default.
74246853Sdes * This can be disabled using <code>setWheelScrollingEnabled</code>.
75246853Sdes * Wheel scrolling can be customized by setting the block and
76246853Sdes * unit increment of the horizontal and vertical Adjustables.
77246853Sdes * For information on how mouse wheel events are dispatched, see
78246853Sdes * the class description for {@link MouseWheelEvent}.
79246853Sdes * <P>
80246853Sdes * Insets are used to define any space used by scrollbars and any
81246853Sdes * borders created by the scroll pane. getInsets() can be used
82246853Sdes * to get the current value for the insets.  If the value of
83246853Sdes * scrollbarsAlwaysVisible is false, then the value of the insets
84246853Sdes * will change dynamically depending on whether the scrollbars are
85246853Sdes * currently visible or not.
86246853Sdes *
87246853Sdes * @author      Tom Ball
88246853Sdes * @author      Amy Fowler
89246853Sdes * @author      Tim Prinzing
90246853Sdes */
91246853Sdespublic class ScrollPane extends Container implements Accessible {
92246853Sdes
93246853Sdes
94246853Sdes    /**
95246853Sdes     * Initialize JNI field and method IDs
96246853Sdes     */
97246853Sdes    private static native void initIDs();
98246853Sdes
99246853Sdes    static {
100246853Sdes        /* ensure that the necessary native libraries are loaded */
101246853Sdes        Toolkit.loadLibraries();
102246853Sdes        if (!GraphicsEnvironment.isHeadless()) {
103246853Sdes            initIDs();
104246853Sdes        }
105246853Sdes    }
106246853Sdes
107246853Sdes    /**
108246853Sdes     * Specifies that horizontal/vertical scrollbar should be shown
109246853Sdes     * only when the size of the child exceeds the size of the scrollpane
110246853Sdes     * in the horizontal/vertical dimension.
111246853Sdes     */
112246853Sdes    public static final int SCROLLBARS_AS_NEEDED = 0;
113246853Sdes
114246853Sdes    /**
115246853Sdes     * Specifies that horizontal/vertical scrollbars should always be
116246853Sdes     * shown regardless of the respective sizes of the scrollpane and child.
117246853Sdes     */
118246853Sdes    public static final int SCROLLBARS_ALWAYS = 1;
119246853Sdes
120246853Sdes    /**
121246853Sdes     * Specifies that horizontal/vertical scrollbars should never be shown
122246853Sdes     * regardless of the respective sizes of the scrollpane and child.
123246853Sdes     */
124246853Sdes    public static final int SCROLLBARS_NEVER = 2;
125246853Sdes
126246853Sdes    /**
127246853Sdes     * There are 3 ways in which a scroll bar can be displayed.
128246853Sdes     * This integer will represent one of these 3 displays -
129246853Sdes     * (SCROLLBARS_ALWAYS, SCROLLBARS_AS_NEEDED, SCROLLBARS_NEVER)
130246853Sdes     *
131246853Sdes     * @serial
132246853Sdes     * @see #getScrollbarDisplayPolicy
133246853Sdes     */
134246853Sdes    private int scrollbarDisplayPolicy;
135246853Sdes
136246853Sdes    /**
137246853Sdes     * An adjustable vertical scrollbar.
138246853Sdes     * It is important to note that you must <em>NOT</em> call 3
139246853Sdes     * <code>Adjustable</code> methods, namely:
140246853Sdes     * <code>setMinimum()</code>, <code>setMaximum()</code>,
141246853Sdes     * <code>setVisibleAmount()</code>.
142246853Sdes     *
143246853Sdes     * @serial
144246853Sdes     * @see #getVAdjustable
145246853Sdes     */
146246853Sdes    private ScrollPaneAdjustable vAdjustable;
147246853Sdes
148246853Sdes    /**
149246853Sdes     * An adjustable horizontal scrollbar.
150246853Sdes     * It is important to note that you must <em>NOT</em> call 3
151246853Sdes     * <code>Adjustable</code> methods, namely:
152246853Sdes     * <code>setMinimum()</code>, <code>setMaximum()</code>,
153246853Sdes     * <code>setVisibleAmount()</code>.
154246853Sdes     *
155246853Sdes     * @serial
156246853Sdes     * @see #getHAdjustable
157246853Sdes     */
158246853Sdes    private ScrollPaneAdjustable hAdjustable;
159246853Sdes
160246853Sdes    private static final String base = "scrollpane";
161246853Sdes    private static int nameCounter = 0;
162246853Sdes
163246853Sdes    private static final boolean defaultWheelScroll = true;
164246853Sdes
165246853Sdes    /**
166246853Sdes     * Indicates whether or not scrolling should take place when a
167246853Sdes     * MouseWheelEvent is received.
168246853Sdes     *
169246853Sdes     * @serial
170246853Sdes     * @since 1.4
171246853Sdes     */
172246853Sdes    private boolean wheelScrollingEnabled = defaultWheelScroll;
173246853Sdes
174246853Sdes    /*
175246853Sdes     * JDK 1.1 serialVersionUID
176246853Sdes     */
177246853Sdes    private static final long serialVersionUID = 7956609840827222915L;
178246853Sdes
179246853Sdes    /**
180246853Sdes     * Create a new scrollpane container with a scrollbar display
181246853Sdes     * policy of "as needed".
182246853Sdes     * @throws HeadlessException if GraphicsEnvironment.isHeadless()
183246853Sdes     *     returns true
184246853Sdes     * @see java.awt.GraphicsEnvironment#isHeadless
185246853Sdes     */
186246853Sdes    public ScrollPane() throws HeadlessException {
187246853Sdes        this(SCROLLBARS_AS_NEEDED);
188246853Sdes    }
189246853Sdes
190246853Sdes    /**
191246853Sdes     * Create a new scrollpane container.
192246853Sdes     * @param scrollbarDisplayPolicy policy for when scrollbars should be shown
193246853Sdes     * @throws IllegalArgumentException if the specified scrollbar
194246853Sdes     *     display policy is invalid
195246853Sdes     * @throws HeadlessException if GraphicsEnvironment.isHeadless()
196246853Sdes     *     returns true
197246853Sdes     * @see java.awt.GraphicsEnvironment#isHeadless
198246853Sdes     */
199246853Sdes    @ConstructorProperties({"scrollbarDisplayPolicy"})
200246853Sdes    public ScrollPane(int scrollbarDisplayPolicy) throws HeadlessException {
201246853Sdes        GraphicsEnvironment.checkHeadless();
202246853Sdes        this.layoutMgr = null;
203246853Sdes        this.width = 100;
204246853Sdes        this.height = 100;
205246853Sdes        switch (scrollbarDisplayPolicy) {
206246853Sdes            case SCROLLBARS_NEVER:
207246853Sdes            case SCROLLBARS_AS_NEEDED:
208246853Sdes            case SCROLLBARS_ALWAYS:
209246853Sdes                this.scrollbarDisplayPolicy = scrollbarDisplayPolicy;
210246853Sdes                break;
211246853Sdes            default:
212246853Sdes                throw new IllegalArgumentException("illegal scrollbar display policy");
213246853Sdes        }
214246853Sdes
215246853Sdes        vAdjustable = new ScrollPaneAdjustable(this, new PeerFixer(this),
216246853Sdes                                               Adjustable.VERTICAL);
217246853Sdes        hAdjustable = new ScrollPaneAdjustable(this, new PeerFixer(this),
218246853Sdes                                               Adjustable.HORIZONTAL);
219246853Sdes        setWheelScrollingEnabled(defaultWheelScroll);
220246853Sdes    }
221246853Sdes
222246853Sdes    /**
223246853Sdes     * Construct a name for this component.  Called by getName() when the
224246853Sdes     * name is null.
225246853Sdes     */
226246853Sdes    String constructComponentName() {
227246853Sdes        synchronized (ScrollPane.class) {
228246853Sdes            return base + nameCounter++;
229246853Sdes        }
230246853Sdes    }
231246853Sdes
232246853Sdes    // The scrollpane won't work with a windowless child... it assumes
233246853Sdes    // it is moving a child window around so the windowless child is
234246853Sdes    // wrapped with a window.
235246853Sdes    private void addToPanel(Component comp, Object constraints, int index) {
236246853Sdes        Panel child = new Panel();
237246853Sdes        child.setLayout(new BorderLayout());
238246853Sdes        child.add(comp);
239246853Sdes        super.addImpl(child, constraints, index);
240246853Sdes        validate();
241246853Sdes    }
242246853Sdes
243246853Sdes    /**
244246853Sdes     * Adds the specified component to this scroll pane container.
245246853Sdes     * If the scroll pane has an existing child component, that
246246853Sdes     * component is removed and the new one is added.
247246853Sdes     * @param comp the component to be added
248246853Sdes     * @param constraints  not applicable
249246853Sdes     * @param index position of child component (must be &lt;= 0)
250246853Sdes     */
251246853Sdes    protected final void addImpl(Component comp, Object constraints, int index) {
252246853Sdes        synchronized (getTreeLock()) {
253246853Sdes            if (getComponentCount() > 0) {
254246853Sdes                remove(0);
255246853Sdes            }
256246853Sdes            if (index > 0) {
257246853Sdes                throw new IllegalArgumentException("position greater than 0");
258246853Sdes            }
259246853Sdes
260246853Sdes            if (!SunToolkit.isLightweightOrUnknown(comp)) {
261246853Sdes                super.addImpl(comp, constraints, index);
262246853Sdes            } else {
263246853Sdes                addToPanel(comp, constraints, index);
264246853Sdes            }
265246853Sdes        }
266246853Sdes    }
267246853Sdes
268246853Sdes    /**
269246853Sdes     * Returns the display policy for the scrollbars.
270246853Sdes     * @return the display policy for the scrollbars
271246854Sdes     */
272246854Sdes    public int getScrollbarDisplayPolicy() {
273246853Sdes        return scrollbarDisplayPolicy;
274246853Sdes    }
275246853Sdes
276246853Sdes    /**
277246853Sdes     * Returns the current size of the scroll pane's view port.
278246853Sdes     * @return the size of the view port in pixels
279246853Sdes     */
280246853Sdes    public Dimension getViewportSize() {
281246853Sdes        Insets i = getInsets();
282246853Sdes        return new Dimension(width - i.right - i.left,
283246853Sdes                             height - i.top - i.bottom);
284246853Sdes    }
285246853Sdes
286246853Sdes    /**
287246853Sdes     * Returns the height that would be occupied by a horizontal
288246853Sdes     * scrollbar, which is independent of whether it is currently
289246853Sdes     * displayed by the scroll pane or not.
290246853Sdes     * @return the height of a horizontal scrollbar in pixels
291246853Sdes     */
292246853Sdes    public int getHScrollbarHeight() {
293246853Sdes        int h = 0;
294246853Sdes        if (scrollbarDisplayPolicy != SCROLLBARS_NEVER) {
295246853Sdes            ScrollPanePeer peer = (ScrollPanePeer)this.peer;
296246853Sdes            if (peer != null) {
297246853Sdes                h = peer.getHScrollbarHeight();
298246853Sdes            }
299246853Sdes        }
300246853Sdes        return h;
301246853Sdes    }
302246853Sdes
303246853Sdes    /**
304246853Sdes     * Returns the width that would be occupied by a vertical
305246853Sdes     * scrollbar, which is independent of whether it is currently
306246853Sdes     * displayed by the scroll pane or not.
307246853Sdes     * @return the width of a vertical scrollbar in pixels
308246853Sdes     */
309246853Sdes    public int getVScrollbarWidth() {
310246853Sdes        int w = 0;
311246853Sdes        if (scrollbarDisplayPolicy != SCROLLBARS_NEVER) {
312246853Sdes            ScrollPanePeer peer = (ScrollPanePeer)this.peer;
313246853Sdes            if (peer != null) {
314246853Sdes                w = peer.getVScrollbarWidth();
315246853Sdes            }
316246853Sdes        }
317246853Sdes        return w;
318246853Sdes    }
319246853Sdes
320246853Sdes    /**
321246853Sdes     * Returns the <code>ScrollPaneAdjustable</code> object which
322246853Sdes     * represents the state of the vertical scrollbar.
323246853Sdes     * The declared return type of this method is
324246853Sdes     * <code>Adjustable</code> to maintain backward compatibility.
325246853Sdes     *
326246853Sdes     * @see java.awt.ScrollPaneAdjustable
327246853Sdes     * @return the vertical scrollbar state
328249453Sdes     */
329246853Sdes    public Adjustable getVAdjustable() {
330246853Sdes        return vAdjustable;
331246853Sdes    }
332246853Sdes
333246853Sdes    /**
334246853Sdes     * Returns the <code>ScrollPaneAdjustable</code> object which
335246853Sdes     * represents the state of the horizontal scrollbar.
336246853Sdes     * The declared return type of this method is
337246853Sdes     * <code>Adjustable</code> to maintain backward compatibility.
338246853Sdes     *
339246853Sdes     * @see java.awt.ScrollPaneAdjustable
340246853Sdes     * @return the horizontal scrollbar state
341246853Sdes     */
342246853Sdes    public Adjustable getHAdjustable() {
343246853Sdes        return hAdjustable;
344246853Sdes    }
345246853Sdes
346249453Sdes    /**
347249453Sdes     * Scrolls to the specified position within the child component.
348246853Sdes     * A call to this method is only valid if the scroll pane contains
349246853Sdes     * a child.  Specifying a position outside of the legal scrolling bounds
350246853Sdes     * of the child will scroll to the closest legal position.
351246853Sdes     * Legal bounds are defined to be the rectangle:
352246853Sdes     * x = 0, y = 0, width = (child width - view port width),
353246853Sdes     * height = (child height - view port height).
354246853Sdes     * This is a convenience method which interfaces with the Adjustable
355246853Sdes     * objects which represent the state of the scrollbars.
356246853Sdes     * @param x the x position to scroll to
357246853Sdes     * @param y the y position to scroll to
358246853Sdes     * @throws NullPointerException if the scrollpane does not contain
359246853Sdes     *     a child
360246853Sdes     */
361249453Sdes    public void setScrollPosition(int x, int y) {
362249453Sdes        synchronized (getTreeLock()) {
363249453Sdes            if (getComponentCount()==0) {
364249453Sdes                throw new NullPointerException("child is null");
365249453Sdes            }
366249453Sdes            hAdjustable.setValue(x);
367249453Sdes            vAdjustable.setValue(y);
368249453Sdes        }
369249453Sdes    }
370249453Sdes
371249453Sdes    /**
372249453Sdes     * Scrolls to the specified position within the child component.
373249453Sdes     * A call to this method is only valid if the scroll pane contains
374249453Sdes     * a child and the specified position is within legal scrolling bounds
375249453Sdes     * of the child.  Specifying a position outside of the legal scrolling
376249453Sdes     * bounds of the child will scroll to the closest legal position.
377249453Sdes     * Legal bounds are defined to be the rectangle:
378249453Sdes     * x = 0, y = 0, width = (child width - view port width),
379249453Sdes     * height = (child height - view port height).
380249453Sdes     * This is a convenience method which interfaces with the Adjustable
381249453Sdes     * objects which represent the state of the scrollbars.
382249453Sdes     * @param p the Point representing the position to scroll to
383249453Sdes     * @throws NullPointerException if {@code p} is {@code null}
384249453Sdes     */
385246853Sdes    public void setScrollPosition(Point p) {
386246853Sdes        setScrollPosition(p.x, p.y);
387246853Sdes    }
388246853Sdes
389246853Sdes    /**
390246853Sdes     * Returns the current x,y position within the child which is displayed
391246853Sdes     * at the 0,0 location of the scrolled panel's view port.
392246853Sdes     * 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
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     */
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     */
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</code>. 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</code>.
581     *
582     * @return the parameter string of this scroll pane
583     */
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
607    void autoProcessMouseWheel(MouseWheelEvent e) {
608        processMouseWheelEvent(e);
609    }
610
611    /**
612     * Process mouse wheel events that are delivered to this
613     * <code>ScrollPane</code> by scrolling an appropriate amount.
614     * <p>Note that if the event parameter is <code>null</code>
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     */
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     */
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</code> if scrolling should be done
647     *                      automatically for a MouseWheelEvent,
648     *                      <code>false</code> otherwise.
649     * @see #isWheelScrollingEnabled
650     * @see java.awt.event.MouseWheelEvent
651     * @see java.awt.event.MouseWheelListener
652     * @since 1.4
653     */
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     */
668    public boolean isWheelScrollingEnabled() {
669        return wheelScrollingEnabled;
670    }
671
672
673    /**
674     * Writes default serializable fields to stream.
675     */
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()</code> returns
687     * <code>true</code>
688     * @see java.awt.GraphicsEnvironment#isHeadless
689     */
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
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")
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     */
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</code> 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         */
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 */
820class PeerFixer implements AdjustmentListener, java.io.Serializable {
821    /*
822     * serialVersionUID
823     */
824    private static final long serialVersionUID = 7051237413532574756L;
825
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")
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