/* * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package javax.swing; import javax.swing.plaf.*; import javax.swing.border.*; import javax.swing.event.*; import javax.accessibility.*; import java.awt.Component; import java.awt.ComponentOrientation; import java.awt.Rectangle; import java.awt.Insets; import java.awt.LayoutManager; import java.awt.Point; import java.io.ObjectOutputStream; import java.io.IOException; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.Transient; /** * Provides a scrollable view of a lightweight component. * A JScrollPane manages a viewport, optional * vertical and horizontal scroll bars, and optional row and * column heading viewports. * You can find task-oriented documentation of JScrollPane in * How to Use Scroll Panes, * a section in The Java Tutorial. Note that * JScrollPane does not support heavyweight components. *

* * * * *
*

The following text describes this image. *

* The JViewport provides a window, * or "viewport" onto a data * source -- for example, a text file. That data source is the * "scrollable client" (aka data model) displayed by the * JViewport view. * A JScrollPane basically consists of JScrollBars, * a JViewport, and the wiring between them, * as shown in the diagram at right. *

* In addition to the scroll bars and viewport, * a JScrollPane can have a * column header and a row header. Each of these is a * JViewport object that * you specify with setRowHeaderView, * and setColumnHeaderView. * The column header viewport automatically scrolls left and right, tracking * the left-right scrolling of the main viewport. * (It never scrolls vertically, however.) * The row header acts in a similar fashion. *

* Where two scroll bars meet, the row header meets the column header, * or a scroll bar meets one of the headers, both components stop short * of the corner, leaving a rectangular space which is, by default, empty. * These spaces can potentially exist in any number of the four corners. * In the previous diagram, the top right space is present and identified * by the label "corner component". *

* Any number of these empty spaces can be replaced by using the * setCorner method to add a component to a particular corner. * (Note: The same component cannot be added to multiple corners.) * This is useful if there's * some extra decoration or function you'd like to add to the scroll pane. * The size of each corner component is entirely determined by the size of the * headers and/or scroll bars that surround it. *

* A corner component will only be visible if there is an empty space in that * corner for it to exist in. For example, consider a component set into the * top right corner of a scroll pane with a column header. If the scroll pane's * vertical scrollbar is not present, perhaps because the view component hasn't * grown large enough to require it, then the corner component will not be * shown (since there is no empty space in that corner created by the meeting * of the header and vertical scroll bar). Forcing the scroll bar to always be * shown, using * setVerticalScrollBarPolicy(VERTICAL_SCROLLBAR_ALWAYS), * will ensure that the space for the corner component always exists. *

* To add a border around the main viewport, * you can use setViewportBorder. * (Of course, you can also add a border around the whole scroll pane using * setBorder.) *

* A common operation to want to do is to set the background color that will * be used if the main viewport view is smaller than the viewport, or is * not opaque. This can be accomplished by setting the background color * of the viewport, via scrollPane.getViewport().setBackground(). * The reason for setting the color of the viewport and not the scrollpane * is that by default JViewport is opaque * which, among other things, means it will completely fill * in its background using its background color. Therefore when * JScrollPane draws its background the viewport will * usually draw over it. *

* By default JScrollPane uses ScrollPaneLayout * to handle the layout of its child Components. ScrollPaneLayout * determines the size to make the viewport view in one of two ways: *

    *
  1. If the view implements Scrollable * a combination of getPreferredScrollableViewportSize, * getScrollableTracksViewportWidth and * getScrollableTracksViewportHeightis used, otherwise *
  2. getPreferredSize is used. *
*

* Warning: Swing is not thread safe. For more * information see Swing's Threading * Policy. *

* Warning: * Serialized objects of this class will not be compatible with * future Swing releases. The current serialization support is * appropriate for short term storage or RMI between applications running * the same version of Swing. As of 1.4, support for long term storage * of all JavaBeansTM * has been added to the java.beans package. * Please see {@link java.beans.XMLEncoder}. * * @see JScrollBar * @see JViewport * @see ScrollPaneLayout * @see Scrollable * @see Component#getPreferredSize * @see #setViewportView * @see #setRowHeaderView * @see #setColumnHeaderView * @see #setCorner * @see #setViewportBorder * * @beaninfo * attribute: isContainer true * attribute: containerDelegate getViewport * description: A specialized container that manages a viewport, optional scrollbars and headers * * @author Hans Muller */ public class JScrollPane extends JComponent implements ScrollPaneConstants, Accessible { private Border viewportBorder; /** * @see #getUIClassID * @see #readObject */ private static final String uiClassID = "ScrollPaneUI"; /** * The display policy for the vertical scrollbar. * The default is * ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED. * @see #setVerticalScrollBarPolicy */ protected int verticalScrollBarPolicy = VERTICAL_SCROLLBAR_AS_NEEDED; /** * The display policy for the horizontal scrollbar. * The default is * ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED. * @see #setHorizontalScrollBarPolicy */ protected int horizontalScrollBarPolicy = HORIZONTAL_SCROLLBAR_AS_NEEDED; /** * The scrollpane's viewport child. Default is an empty * JViewport. * @see #setViewport */ protected JViewport viewport; /** * The scrollpane's vertical scrollbar child. * Default is a JScrollBar. * @see #setVerticalScrollBar */ protected JScrollBar verticalScrollBar; /** * The scrollpane's horizontal scrollbar child. * Default is a JScrollBar. * @see #setHorizontalScrollBar */ protected JScrollBar horizontalScrollBar; /** * The row header child. Default is null. * @see #setRowHeader */ protected JViewport rowHeader; /** * The column header child. Default is null. * @see #setColumnHeader */ protected JViewport columnHeader; /** * The component to display in the lower left corner. * Default is null. * @see #setCorner */ protected Component lowerLeft; /** * The component to display in the lower right corner. * Default is null. * @see #setCorner */ protected Component lowerRight; /** * The component to display in the upper left corner. * Default is null. * @see #setCorner */ protected Component upperLeft; /** * The component to display in the upper right corner. * Default is null. * @see #setCorner */ protected Component upperRight; /* * State flag for mouse wheel scrolling */ private boolean wheelScrollState = true; /** * Creates a JScrollPane that displays the view * component in a viewport * whose view position can be controlled with a pair of scrollbars. * The scrollbar policies specify when the scrollbars are displayed, * For example, if vsbPolicy is * VERTICAL_SCROLLBAR_AS_NEEDED * then the vertical scrollbar only appears if the view doesn't fit * vertically. The available policy settings are listed at * {@link #setVerticalScrollBarPolicy} and * {@link #setHorizontalScrollBarPolicy}. * * @see #setViewportView * * @param view the component to display in the scrollpanes viewport * @param vsbPolicy an integer that specifies the vertical * scrollbar policy * @param hsbPolicy an integer that specifies the horizontal * scrollbar policy */ public JScrollPane(Component view, int vsbPolicy, int hsbPolicy) { setLayout(new ScrollPaneLayout.UIResource()); setVerticalScrollBarPolicy(vsbPolicy); setHorizontalScrollBarPolicy(hsbPolicy); setViewport(createViewport()); setVerticalScrollBar(createVerticalScrollBar()); setHorizontalScrollBar(createHorizontalScrollBar()); if (view != null) { setViewportView(view); } setUIProperty("opaque",true); updateUI(); if (!this.getComponentOrientation().isLeftToRight()) { viewport.setViewPosition(new Point(Integer.MAX_VALUE, 0)); } } /** * Creates a JScrollPane that displays the * contents of the specified * component, where both horizontal and vertical scrollbars appear * whenever the component's contents are larger than the view. * * @see #setViewportView * @param view the component to display in the scrollpane's viewport */ public JScrollPane(Component view) { this(view, VERTICAL_SCROLLBAR_AS_NEEDED, HORIZONTAL_SCROLLBAR_AS_NEEDED); } /** * Creates an empty (no viewport view) JScrollPane * with specified * scrollbar policies. The available policy settings are listed at * {@link #setVerticalScrollBarPolicy} and * {@link #setHorizontalScrollBarPolicy}. * * @see #setViewportView * * @param vsbPolicy an integer that specifies the vertical * scrollbar policy * @param hsbPolicy an integer that specifies the horizontal * scrollbar policy */ public JScrollPane(int vsbPolicy, int hsbPolicy) { this(null, vsbPolicy, hsbPolicy); } /** * Creates an empty (no viewport view) JScrollPane * where both horizontal and vertical scrollbars appear when needed. */ public JScrollPane() { this(null, VERTICAL_SCROLLBAR_AS_NEEDED, HORIZONTAL_SCROLLBAR_AS_NEEDED); } /** * Returns the look and feel (L&F) object that renders this component. * * @return the ScrollPaneUI object that renders this * component * @see #setUI * @beaninfo * bound: true * hidden: true * attribute: visualUpdate true * description: The UI object that implements the Component's LookAndFeel. */ public ScrollPaneUI getUI() { return (ScrollPaneUI)ui; } /** * Sets the ScrollPaneUI object that provides the * look and feel (L&F) for this component. * * @param ui the ScrollPaneUI L&F object * @see #getUI */ public void setUI(ScrollPaneUI ui) { super.setUI(ui); } /** * Replaces the current ScrollPaneUI object with a version * from the current default look and feel. * To be called when the default look and feel changes. * * @see JComponent#updateUI * @see UIManager#getUI */ public void updateUI() { setUI((ScrollPaneUI)UIManager.getUI(this)); } /** * Returns the suffix used to construct the name of the L&F class used to * render this component. * * @return the string "ScrollPaneUI" * @see JComponent#getUIClassID * @see UIDefaults#getUI * * @beaninfo * hidden: true */ public String getUIClassID() { return uiClassID; } /** * Sets the layout manager for this JScrollPane. * This method overrides setLayout in * java.awt.Container to ensure that only * LayoutManagers which * are subclasses of ScrollPaneLayout can be used in a * JScrollPane. If layout is non-null, this * will invoke syncWithScrollPane on it. * * @param layout the specified layout manager * @exception ClassCastException if layout is not a * ScrollPaneLayout * @see java.awt.Container#getLayout * @see java.awt.Container#setLayout * * @beaninfo * hidden: true */ public void setLayout(LayoutManager layout) { if (layout instanceof ScrollPaneLayout) { super.setLayout(layout); ((ScrollPaneLayout)layout).syncWithScrollPane(this); } else if (layout == null) { super.setLayout(layout); } else { String s = "layout of JScrollPane must be a ScrollPaneLayout"; throw new ClassCastException(s); } } /** * Overridden to return true so that any calls to revalidate * on any descendants of this JScrollPane will cause the * entire tree beginning with this JScrollPane to be * validated. * * @return true * @see java.awt.Container#validate * @see JComponent#revalidate * @see JComponent#isValidateRoot * @see java.awt.Container#isValidateRoot * * @beaninfo * hidden: true */ @Override public boolean isValidateRoot() { return true; } /** * Returns the vertical scroll bar policy value. * @return the verticalScrollBarPolicy property * @see #setVerticalScrollBarPolicy */ public int getVerticalScrollBarPolicy() { return verticalScrollBarPolicy; } /** * Determines when the vertical scrollbar appears in the scrollpane. * Legal values are: *

* * @param policy one of the three values listed above * @exception IllegalArgumentException if policy * is not one of the legal values shown above * @see #getVerticalScrollBarPolicy * * @beaninfo * preferred: true * bound: true * description: The scrollpane vertical scrollbar policy * enum: VERTICAL_SCROLLBAR_AS_NEEDED ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED * VERTICAL_SCROLLBAR_NEVER ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER * VERTICAL_SCROLLBAR_ALWAYS ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS */ public void setVerticalScrollBarPolicy(int policy) { switch (policy) { case VERTICAL_SCROLLBAR_AS_NEEDED: case VERTICAL_SCROLLBAR_NEVER: case VERTICAL_SCROLLBAR_ALWAYS: break; default: throw new IllegalArgumentException("invalid verticalScrollBarPolicy"); } int old = verticalScrollBarPolicy; verticalScrollBarPolicy = policy; firePropertyChange("verticalScrollBarPolicy", old, policy); revalidate(); repaint(); } /** * Returns the horizontal scroll bar policy value. * @return the horizontalScrollBarPolicy property * @see #setHorizontalScrollBarPolicy */ public int getHorizontalScrollBarPolicy() { return horizontalScrollBarPolicy; } /** * Determines when the horizontal scrollbar appears in the scrollpane. * The options are: * * @param policy one of the three values listed above * @exception IllegalArgumentException if policy * is not one of the legal values shown above * @see #getHorizontalScrollBarPolicy * * @beaninfo * preferred: true * bound: true * description: The scrollpane scrollbar policy * enum: HORIZONTAL_SCROLLBAR_AS_NEEDED ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED * HORIZONTAL_SCROLLBAR_NEVER ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER * HORIZONTAL_SCROLLBAR_ALWAYS ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS */ public void setHorizontalScrollBarPolicy(int policy) { switch (policy) { case HORIZONTAL_SCROLLBAR_AS_NEEDED: case HORIZONTAL_SCROLLBAR_NEVER: case HORIZONTAL_SCROLLBAR_ALWAYS: break; default: throw new IllegalArgumentException("invalid horizontalScrollBarPolicy"); } int old = horizontalScrollBarPolicy; horizontalScrollBarPolicy = policy; firePropertyChange("horizontalScrollBarPolicy", old, policy); revalidate(); repaint(); } /** * Returns the Border object that surrounds the viewport. * * @return the viewportBorder property * @see #setViewportBorder */ public Border getViewportBorder() { return viewportBorder; } /** * Adds a border around the viewport. Note that the border isn't * set on the viewport directly, JViewport doesn't support * the JComponent border property. * Similarly setting the JScrollPanes * viewport doesn't affect the viewportBorder property. *

* The default value of this property is computed by the look * and feel implementation. * * @param viewportBorder the border to be added * @see #getViewportBorder * @see #setViewport * * @beaninfo * preferred: true * bound: true * description: The border around the viewport. */ public void setViewportBorder(Border viewportBorder) { Border oldValue = this.viewportBorder; this.viewportBorder = viewportBorder; firePropertyChange("viewportBorder", oldValue, viewportBorder); } /** * Returns the bounds of the viewport's border. * * @return a Rectangle object specifying the viewport border */ public Rectangle getViewportBorderBounds() { Rectangle borderR = new Rectangle(getSize()); Insets insets = getInsets(); borderR.x = insets.left; borderR.y = insets.top; borderR.width -= insets.left + insets.right; borderR.height -= insets.top + insets.bottom; boolean leftToRight = SwingUtilities.isLeftToRight(this); /* If there's a visible column header remove the space it * needs from the top of borderR. */ JViewport colHead = getColumnHeader(); if ((colHead != null) && (colHead.isVisible())) { int colHeadHeight = colHead.getHeight(); borderR.y += colHeadHeight; borderR.height -= colHeadHeight; } /* If there's a visible row header remove the space it needs * from the left of borderR. */ JViewport rowHead = getRowHeader(); if ((rowHead != null) && (rowHead.isVisible())) { int rowHeadWidth = rowHead.getWidth(); if ( leftToRight ) { borderR.x += rowHeadWidth; } borderR.width -= rowHeadWidth; } /* If there's a visible vertical scrollbar remove the space it needs * from the width of borderR. */ JScrollBar vsb = getVerticalScrollBar(); if ((vsb != null) && (vsb.isVisible())) { int vsbWidth = vsb.getWidth(); if ( !leftToRight ) { borderR.x += vsbWidth; } borderR.width -= vsbWidth; } /* If there's a visible horizontal scrollbar remove the space it needs * from the height of borderR. */ JScrollBar hsb = getHorizontalScrollBar(); if ((hsb != null) && (hsb.isVisible())) { borderR.height -= hsb.getHeight(); } return borderR; } /** * By default JScrollPane creates scrollbars * that are instances * of this class. Scrollbar overrides the * getUnitIncrement and getBlockIncrement * methods so that, if the viewport's view is a Scrollable, * the view is asked to compute these values. Unless * the unit/block increment have been explicitly set. *

* Warning: * Serialized objects of this class will not be compatible with * future Swing releases. The current serialization support is * appropriate for short term storage or RMI between applications running * the same version of Swing. As of 1.4, support for long term storage * of all JavaBeansTM * has been added to the java.beans package. * Please see {@link java.beans.XMLEncoder}. * * @see Scrollable * @see JScrollPane#createVerticalScrollBar * @see JScrollPane#createHorizontalScrollBar */ protected class ScrollBar extends JScrollBar implements UIResource { /** * Set to true when the unit increment has been explicitly set. * If this is false the viewport's view is obtained and if it * is an instance of Scrollable the unit increment * from it is used. */ private boolean unitIncrementSet; /** * Set to true when the block increment has been explicitly set. * If this is false the viewport's view is obtained and if it * is an instance of Scrollable the block increment * from it is used. */ private boolean blockIncrementSet; /** * Creates a scrollbar with the specified orientation. * The options are: *

* * @param orientation an integer specifying one of the legal * orientation values shown above * @since 1.4 */ public ScrollBar(int orientation) { super(orientation); this.putClientProperty("JScrollBar.fastWheelScrolling", Boolean.TRUE); } /** * Messages super to set the value, and resets the * unitIncrementSet instance variable to true. * * @param unitIncrement the new unit increment value, in pixels */ public void setUnitIncrement(int unitIncrement) { unitIncrementSet = true; this.putClientProperty("JScrollBar.fastWheelScrolling", null); super.setUnitIncrement(unitIncrement); } /** * Computes the unit increment for scrolling if the viewport's * view is a Scrollable object. * Otherwise return super.getUnitIncrement. * * @param direction less than zero to scroll up/left, * greater than zero for down/right * @return an integer, in pixels, containing the unit increment * @see Scrollable#getScrollableUnitIncrement */ public int getUnitIncrement(int direction) { JViewport vp = getViewport(); if (!unitIncrementSet && (vp != null) && (vp.getView() instanceof Scrollable)) { Scrollable view = (Scrollable)(vp.getView()); Rectangle vr = vp.getViewRect(); return view.getScrollableUnitIncrement(vr, getOrientation(), direction); } else { return super.getUnitIncrement(direction); } } /** * Messages super to set the value, and resets the * blockIncrementSet instance variable to true. * * @param blockIncrement the new block increment value, in pixels */ public void setBlockIncrement(int blockIncrement) { blockIncrementSet = true; this.putClientProperty("JScrollBar.fastWheelScrolling", null); super.setBlockIncrement(blockIncrement); } /** * Computes the block increment for scrolling if the viewport's * view is a Scrollable object. Otherwise * the blockIncrement equals the viewport's width * or height. If there's no viewport return * super.getBlockIncrement. * * @param direction less than zero to scroll up/left, * greater than zero for down/right * @return an integer, in pixels, containing the block increment * @see Scrollable#getScrollableBlockIncrement */ public int getBlockIncrement(int direction) { JViewport vp = getViewport(); if (blockIncrementSet || vp == null) { return super.getBlockIncrement(direction); } else if (vp.getView() instanceof Scrollable) { Scrollable view = (Scrollable)(vp.getView()); Rectangle vr = vp.getViewRect(); return view.getScrollableBlockIncrement(vr, getOrientation(), direction); } else if (getOrientation() == VERTICAL) { return vp.getExtentSize().height; } else { return vp.getExtentSize().width; } } } /** * Returns a JScrollPane.ScrollBar by default. * Subclasses may override this method to force ScrollPaneUI * implementations to use a JScrollBar subclass. * Used by ScrollPaneUI implementations to * create the horizontal scrollbar. * * @return a JScrollBar with a horizontal orientation * @see JScrollBar */ public JScrollBar createHorizontalScrollBar() { return new ScrollBar(JScrollBar.HORIZONTAL); } /** * Returns the horizontal scroll bar that controls the viewport's * horizontal view position. * * @return the horizontalScrollBar property * @see #setHorizontalScrollBar */ @Transient public JScrollBar getHorizontalScrollBar() { return horizontalScrollBar; } /** * Adds the scrollbar that controls the viewport's horizontal view * position to the scrollpane. * This is usually unnecessary, as JScrollPane creates * horizontal and vertical scrollbars by default. * * @param horizontalScrollBar the horizontal scrollbar to be added * @see #createHorizontalScrollBar * @see #getHorizontalScrollBar * * @beaninfo * expert: true * bound: true * description: The horizontal scrollbar. */ public void setHorizontalScrollBar(JScrollBar horizontalScrollBar) { JScrollBar old = getHorizontalScrollBar(); this.horizontalScrollBar = horizontalScrollBar; if (horizontalScrollBar != null) { add(horizontalScrollBar, HORIZONTAL_SCROLLBAR); } else if (old != null) { remove(old); } firePropertyChange("horizontalScrollBar", old, horizontalScrollBar); revalidate(); repaint(); } /** * Returns a JScrollPane.ScrollBar by default. Subclasses * may override this method to force ScrollPaneUI * implementations to use a JScrollBar subclass. * Used by ScrollPaneUI implementations to create the * vertical scrollbar. * * @return a JScrollBar with a vertical orientation * @see JScrollBar */ public JScrollBar createVerticalScrollBar() { return new ScrollBar(JScrollBar.VERTICAL); } /** * Returns the vertical scroll bar that controls the viewports * vertical view position. * * @return the verticalScrollBar property * @see #setVerticalScrollBar */ @Transient public JScrollBar getVerticalScrollBar() { return verticalScrollBar; } /** * Adds the scrollbar that controls the viewports vertical view position * to the scrollpane. This is usually unnecessary, * as JScrollPane creates vertical and * horizontal scrollbars by default. * * @param verticalScrollBar the new vertical scrollbar to be added * @see #createVerticalScrollBar * @see #getVerticalScrollBar * * @beaninfo * expert: true * bound: true * description: The vertical scrollbar. */ public void setVerticalScrollBar(JScrollBar verticalScrollBar) { JScrollBar old = getVerticalScrollBar(); this.verticalScrollBar = verticalScrollBar; add(verticalScrollBar, VERTICAL_SCROLLBAR); firePropertyChange("verticalScrollBar", old, verticalScrollBar); revalidate(); repaint(); } /** * Returns a new JViewport by default. * Used to create the * viewport (as needed) in setViewportView, * setRowHeaderView, and setColumnHeaderView. * Subclasses may override this method to return a subclass of * JViewport. * * @return a new JViewport */ protected JViewport createViewport() { return new JViewport(); } /** * Returns the current JViewport. * * @see #setViewport * @return the viewport property */ public JViewport getViewport() { return viewport; } /** * Removes the old viewport (if there is one); forces the * viewPosition of the new viewport to be in the +x,+y quadrant; * syncs up the row and column headers (if there are any) with the * new viewport; and finally syncs the scrollbars and * headers with the new viewport. *

* Most applications will find it more convenient to use * setViewportView * to add a viewport and a view to the scrollpane. * * @param viewport the new viewport to be used; if viewport is * null, the old viewport is still removed * and the new viewport is set to null * @see #createViewport * @see #getViewport * @see #setViewportView * * @beaninfo * expert: true * bound: true * attribute: visualUpdate true * description: The viewport child for this scrollpane * */ public void setViewport(JViewport viewport) { JViewport old = getViewport(); this.viewport = viewport; if (viewport != null) { add(viewport, VIEWPORT); } else if (old != null) { remove(old); } firePropertyChange("viewport", old, viewport); if (accessibleContext != null) { ((AccessibleJScrollPane)accessibleContext).resetViewPort(); } revalidate(); repaint(); } /** * Creates a viewport if necessary and then sets its view. Applications * that don't provide the view directly to the JScrollPane * constructor * should use this method to specify the scrollable child that's going * to be displayed in the scrollpane. For example: *

     * JScrollPane scrollpane = new JScrollPane();
     * scrollpane.setViewportView(myBigComponentToScroll);
     * 
* Applications should not add children directly to the scrollpane. * * @param view the component to add to the viewport * @see #setViewport * @see JViewport#setView */ public void setViewportView(Component view) { if (getViewport() == null) { setViewport(createViewport()); } getViewport().setView(view); } /** * Returns the row header. * @return the rowHeader property * @see #setRowHeader */ @Transient public JViewport getRowHeader() { return rowHeader; } /** * Removes the old rowHeader, if it exists; if the new rowHeader * isn't null, syncs the y coordinate of its * viewPosition with * the viewport (if there is one) and then adds it to the scroll pane. *

* Most applications will find it more convenient to use * setRowHeaderView * to add a row header component and its viewport to the scroll pane. * * @param rowHeader the new row header to be used; if null * the old row header is still removed and the new rowHeader * is set to null * @see #getRowHeader * @see #setRowHeaderView * * @beaninfo * bound: true * expert: true * description: The row header child for this scrollpane */ public void setRowHeader(JViewport rowHeader) { JViewport old = getRowHeader(); this.rowHeader = rowHeader; if (rowHeader != null) { add(rowHeader, ROW_HEADER); } else if (old != null) { remove(old); } firePropertyChange("rowHeader", old, rowHeader); revalidate(); repaint(); } /** * Creates a row-header viewport if necessary, sets * its view and then adds the row-header viewport * to the scrollpane. For example: *

     * JScrollPane scrollpane = new JScrollPane();
     * scrollpane.setViewportView(myBigComponentToScroll);
     * scrollpane.setRowHeaderView(myBigComponentsRowHeader);
     * 
* * @see #setRowHeader * @see JViewport#setView * @param view the component to display as the row header */ public void setRowHeaderView(Component view) { if (getRowHeader() == null) { setRowHeader(createViewport()); } getRowHeader().setView(view); } /** * Returns the column header. * @return the columnHeader property * @see #setColumnHeader */ @Transient public JViewport getColumnHeader() { return columnHeader; } /** * Removes the old columnHeader, if it exists; if the new columnHeader * isn't null, syncs the x coordinate of its viewPosition * with the viewport (if there is one) and then adds it to the scroll pane. *

* Most applications will find it more convenient to use * setColumnHeaderView * to add a column header component and its viewport to the scroll pane. * * @see #getColumnHeader * @see #setColumnHeaderView * * @beaninfo * bound: true * description: The column header child for this scrollpane * attribute: visualUpdate true */ public void setColumnHeader(JViewport columnHeader) { JViewport old = getColumnHeader(); this.columnHeader = columnHeader; if (columnHeader != null) { add(columnHeader, COLUMN_HEADER); } else if (old != null) { remove(old); } firePropertyChange("columnHeader", old, columnHeader); revalidate(); repaint(); } /** * Creates a column-header viewport if necessary, sets * its view, and then adds the column-header viewport * to the scrollpane. For example: *

     * JScrollPane scrollpane = new JScrollPane();
     * scrollpane.setViewportView(myBigComponentToScroll);
     * scrollpane.setColumnHeaderView(myBigComponentsColumnHeader);
     * 
* * @see #setColumnHeader * @see JViewport#setView * * @param view the component to display as the column header */ public void setColumnHeaderView(Component view) { if (getColumnHeader() == null) { setColumnHeader(createViewport()); } getColumnHeader().setView(view); } /** * Returns the component at the specified corner. The * key value specifying the corner is one of: * * * @param key one of the values as shown above * @return the corner component (which may be null) * identified by the given key, or null * if the key is invalid * @see #setCorner */ public Component getCorner(String key) { boolean isLeftToRight = getComponentOrientation().isLeftToRight(); if (key.equals(LOWER_LEADING_CORNER)) { key = isLeftToRight ? LOWER_LEFT_CORNER : LOWER_RIGHT_CORNER; } else if (key.equals(LOWER_TRAILING_CORNER)) { key = isLeftToRight ? LOWER_RIGHT_CORNER : LOWER_LEFT_CORNER; } else if (key.equals(UPPER_LEADING_CORNER)) { key = isLeftToRight ? UPPER_LEFT_CORNER : UPPER_RIGHT_CORNER; } else if (key.equals(UPPER_TRAILING_CORNER)) { key = isLeftToRight ? UPPER_RIGHT_CORNER : UPPER_LEFT_CORNER; } if (key.equals(LOWER_LEFT_CORNER)) { return lowerLeft; } else if (key.equals(LOWER_RIGHT_CORNER)) { return lowerRight; } else if (key.equals(UPPER_LEFT_CORNER)) { return upperLeft; } else if (key.equals(UPPER_RIGHT_CORNER)) { return upperRight; } else { return null; } } /** * Adds a child that will appear in one of the scroll panes * corners, if there's room. For example with both scrollbars * showing (on the right and bottom edges of the scrollpane) * the lower left corner component will be shown in the space * between ends of the two scrollbars. Legal values for * the key are: * *

* Although "corner" doesn't match any beans property * signature, PropertyChange events are generated with the * property name set to the corner key. * * @param key identifies which corner the component will appear in * @param corner one of the following components: *

* @exception IllegalArgumentException if corner key is invalid */ public void setCorner(String key, Component corner) { Component old; boolean isLeftToRight = getComponentOrientation().isLeftToRight(); if (key.equals(LOWER_LEADING_CORNER)) { key = isLeftToRight ? LOWER_LEFT_CORNER : LOWER_RIGHT_CORNER; } else if (key.equals(LOWER_TRAILING_CORNER)) { key = isLeftToRight ? LOWER_RIGHT_CORNER : LOWER_LEFT_CORNER; } else if (key.equals(UPPER_LEADING_CORNER)) { key = isLeftToRight ? UPPER_LEFT_CORNER : UPPER_RIGHT_CORNER; } else if (key.equals(UPPER_TRAILING_CORNER)) { key = isLeftToRight ? UPPER_RIGHT_CORNER : UPPER_LEFT_CORNER; } if (key.equals(LOWER_LEFT_CORNER)) { old = lowerLeft; lowerLeft = corner; } else if (key.equals(LOWER_RIGHT_CORNER)) { old = lowerRight; lowerRight = corner; } else if (key.equals(UPPER_LEFT_CORNER)) { old = upperLeft; upperLeft = corner; } else if (key.equals(UPPER_RIGHT_CORNER)) { old = upperRight; upperRight = corner; } else { throw new IllegalArgumentException("invalid corner key"); } if (old != null) { remove(old); } if (corner != null) { add(corner, key); } firePropertyChange(key, old, corner); revalidate(); repaint(); } /** * Sets the orientation for the vertical and horizontal * scrollbars as determined by the * ComponentOrientation argument. * * @param co one of the following values: * * @see java.awt.ComponentOrientation */ public void setComponentOrientation( ComponentOrientation co ) { super.setComponentOrientation( co ); if( verticalScrollBar != null ) verticalScrollBar.setComponentOrientation( co ); if( horizontalScrollBar != null ) horizontalScrollBar.setComponentOrientation( co ); } /** * Indicates whether or not scrolling will take place in response to the * mouse wheel. Wheel scrolling is enabled by default. * * @see #setWheelScrollingEnabled * @since 1.4 * @beaninfo * bound: true * description: Flag for enabling/disabling mouse wheel scrolling */ public boolean isWheelScrollingEnabled() {return wheelScrollState;} /** * Enables/disables scrolling in response to movement of the mouse wheel. * Wheel scrolling is enabled by default. * * @param handleWheel true if scrolling should be done * automatically for a MouseWheelEvent, * false otherwise. * @see #isWheelScrollingEnabled * @see java.awt.event.MouseWheelEvent * @see java.awt.event.MouseWheelListener * @since 1.4 * @beaninfo * bound: true * description: Flag for enabling/disabling mouse wheel scrolling */ public void setWheelScrollingEnabled(boolean handleWheel) { boolean old = wheelScrollState; wheelScrollState = handleWheel; firePropertyChange("wheelScrollingEnabled", old, handleWheel); } /** * See readObject and writeObject in * JComponent for more * information about serialization in Swing. */ private void writeObject(ObjectOutputStream s) throws IOException { s.defaultWriteObject(); if (getUIClassID().equals(uiClassID)) { byte count = JComponent.getWriteObjCounter(this); JComponent.setWriteObjCounter(this, --count); if (count == 0 && ui != null) { ui.installUI(this); } } } /** * Returns a string representation of this JScrollPane. * This method * is intended to be used only for debugging purposes, and the * content and format of the returned string may vary between * implementations. The returned string may be empty but may not * be null. * * @return a string representation of this JScrollPane. */ protected String paramString() { String viewportBorderString = (viewportBorder != null ? viewportBorder.toString() : ""); String viewportString = (viewport != null ? viewport.toString() : ""); String verticalScrollBarPolicyString; if (verticalScrollBarPolicy == VERTICAL_SCROLLBAR_AS_NEEDED) { verticalScrollBarPolicyString = "VERTICAL_SCROLLBAR_AS_NEEDED"; } else if (verticalScrollBarPolicy == VERTICAL_SCROLLBAR_NEVER) { verticalScrollBarPolicyString = "VERTICAL_SCROLLBAR_NEVER"; } else if (verticalScrollBarPolicy == VERTICAL_SCROLLBAR_ALWAYS) { verticalScrollBarPolicyString = "VERTICAL_SCROLLBAR_ALWAYS"; } else verticalScrollBarPolicyString = ""; String horizontalScrollBarPolicyString; if (horizontalScrollBarPolicy == HORIZONTAL_SCROLLBAR_AS_NEEDED) { horizontalScrollBarPolicyString = "HORIZONTAL_SCROLLBAR_AS_NEEDED"; } else if (horizontalScrollBarPolicy == HORIZONTAL_SCROLLBAR_NEVER) { horizontalScrollBarPolicyString = "HORIZONTAL_SCROLLBAR_NEVER"; } else if (horizontalScrollBarPolicy == HORIZONTAL_SCROLLBAR_ALWAYS) { horizontalScrollBarPolicyString = "HORIZONTAL_SCROLLBAR_ALWAYS"; } else horizontalScrollBarPolicyString = ""; String horizontalScrollBarString = (horizontalScrollBar != null ? horizontalScrollBar.toString() : ""); String verticalScrollBarString = (verticalScrollBar != null ? verticalScrollBar.toString() : ""); String columnHeaderString = (columnHeader != null ? columnHeader.toString() : ""); String rowHeaderString = (rowHeader != null ? rowHeader.toString() : ""); String lowerLeftString = (lowerLeft != null ? lowerLeft.toString() : ""); String lowerRightString = (lowerRight != null ? lowerRight.toString() : ""); String upperLeftString = (upperLeft != null ? upperLeft.toString() : ""); String upperRightString = (upperRight != null ? upperRight.toString() : ""); return super.paramString() + ",columnHeader=" + columnHeaderString + ",horizontalScrollBar=" + horizontalScrollBarString + ",horizontalScrollBarPolicy=" + horizontalScrollBarPolicyString + ",lowerLeft=" + lowerLeftString + ",lowerRight=" + lowerRightString + ",rowHeader=" + rowHeaderString + ",upperLeft=" + upperLeftString + ",upperRight=" + upperRightString + ",verticalScrollBar=" + verticalScrollBarString + ",verticalScrollBarPolicy=" + verticalScrollBarPolicyString + ",viewport=" + viewportString + ",viewportBorder=" + viewportBorderString; } ///////////////// // Accessibility support //////////////// /** * Gets the AccessibleContext associated with this JScrollPane. * For scroll panes, the AccessibleContext takes the form of an * AccessibleJScrollPane. * A new AccessibleJScrollPane instance is created if necessary. * * @return an AccessibleJScrollPane that serves as the * AccessibleContext of this JScrollPane */ public AccessibleContext getAccessibleContext() { if (accessibleContext == null) { accessibleContext = new AccessibleJScrollPane(); } return accessibleContext; } /** * This class implements accessibility support for the * JScrollPane class. It provides an implementation of the * Java Accessibility API appropriate to scroll pane user-interface * elements. *

* Warning: * Serialized objects of this class will not be compatible with * future Swing releases. The current serialization support is * appropriate for short term storage or RMI between applications running * the same version of Swing. As of 1.4, support for long term storage * of all JavaBeansTM * has been added to the java.beans package. * Please see {@link java.beans.XMLEncoder}. */ protected class AccessibleJScrollPane extends AccessibleJComponent implements ChangeListener, PropertyChangeListener { protected JViewport viewPort = null; /* * Resets the viewport ChangeListener and PropertyChangeListener */ public void resetViewPort() { if (viewPort != null) { viewPort.removeChangeListener(this); viewPort.removePropertyChangeListener(this); } viewPort = JScrollPane.this.getViewport(); if (viewPort != null) { viewPort.addChangeListener(this); viewPort.addPropertyChangeListener(this); } } /** * AccessibleJScrollPane constructor */ public AccessibleJScrollPane() { super(); resetViewPort(); // initialize the AccessibleRelationSets for the JScrollPane // and JScrollBar(s) JScrollBar scrollBar = getHorizontalScrollBar(); if (scrollBar != null) { setScrollBarRelations(scrollBar); } scrollBar = getVerticalScrollBar(); if (scrollBar != null) { setScrollBarRelations(scrollBar); } } /** * Get the role of this object. * * @return an instance of AccessibleRole describing the role of the * object * @see AccessibleRole */ public AccessibleRole getAccessibleRole() { return AccessibleRole.SCROLL_PANE; } /** * Invoked when the target of the listener has changed its state. * * @param e a ChangeEvent object. Must not be null. * * @throws NullPointerException if the parameter is null. */ public void stateChanged(ChangeEvent e) { if (e == null) { throw new NullPointerException(); } firePropertyChange(ACCESSIBLE_VISIBLE_DATA_PROPERTY, Boolean.valueOf(false), Boolean.valueOf(true)); } /** * This method gets called when a bound property is changed. * @param e A PropertyChangeEvent object describing * the event source and the property that has changed. Must not be null. * * @throws NullPointerException if the parameter is null. * @since 1.5 */ public void propertyChange(PropertyChangeEvent e) { String propertyName = e.getPropertyName(); if (propertyName == "horizontalScrollBar" || propertyName == "verticalScrollBar") { if (e.getNewValue() instanceof JScrollBar) { setScrollBarRelations((JScrollBar)e.getNewValue()); } } } /* * Sets the CONTROLLER_FOR and CONTROLLED_BY AccessibleRelations for * the JScrollPane and JScrollBar. JScrollBar must not be null. */ void setScrollBarRelations(JScrollBar scrollBar) { /* * The JScrollBar is a CONTROLLER_FOR the JScrollPane. * The JScrollPane is CONTROLLED_BY the JScrollBar. */ AccessibleRelation controlledBy = new AccessibleRelation(AccessibleRelation.CONTROLLED_BY, scrollBar); AccessibleRelation controllerFor = new AccessibleRelation(AccessibleRelation.CONTROLLER_FOR, JScrollPane.this); // set the relation set for the scroll bar AccessibleContext ac = scrollBar.getAccessibleContext(); ac.getAccessibleRelationSet().add(controllerFor); // set the relation set for the scroll pane getAccessibleRelationSet().add(controlledBy); } } }