/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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.
*/
/**
* The layout manager used by <code>JScrollPane</code>.
* <code>JScrollPaneLayout</code> is
* responsible for nine components: a viewport, two scrollbars,
* a row header, a column header, and four "corner" components.
* <p>
* <strong>Warning:</strong>
* 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 JavaBeans<sup><font size="-2">TM</font></sup>
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @see JScrollPane
* @see JViewport
*
* @author Hans Muller
*/
public class ScrollPaneLayout
{
/**
* The scrollpane's viewport child.
* Default is an empty <code>JViewport</code>.
* @see JScrollPane#setViewport
*/
/**
* The scrollpane's vertical scrollbar child.
* Default is a <code>JScrollBar</code>.
* @see JScrollPane#setVerticalScrollBar
*/
/**
* The scrollpane's horizontal scrollbar child.
* Default is a <code>JScrollBar</code>.
* @see JScrollPane#setHorizontalScrollBar
*/
/**
* The row header child. Default is <code>null</code>.
* @see JScrollPane#setRowHeader
*/
/**
* The column header child. Default is <code>null</code>.
* @see JScrollPane#setColumnHeader
*/
/**
* The component to display in the lower left corner.
* Default is <code>null</code>.
* @see JScrollPane#setCorner
*/
/**
* The component to display in the lower right corner.
* Default is <code>null</code>.
* @see JScrollPane#setCorner
*/
/**
* The component to display in the upper left corner.
* Default is <code>null</code>.
* @see JScrollPane#setCorner
*/
/**
* The component to display in the upper right corner.
* Default is <code>null</code>.
* @see JScrollPane#setCorner
*/
/**
* The display policy for the vertical scrollbar.
* The default is <code>ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED</code>.
* <p>
* This field is obsolete, please use the <code>JScrollPane</code> field instead.
*
* @see JScrollPane#setVerticalScrollBarPolicy
*/
/**
* The display policy for the horizontal scrollbar.
* The default is <code>ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED</code>.
* <p>
* This field is obsolete, please use the <code>JScrollPane</code> field instead.
*
* @see JScrollPane#setHorizontalScrollBarPolicy
*/
/**
* This method is invoked after the ScrollPaneLayout is set as the
* LayoutManager of a <code>JScrollPane</code>.
* It initializes all of the internal fields that
* are ordinarily set by <code>addLayoutComponent</code>. For example:
* <pre>
* ScrollPaneLayout mySPLayout = new ScrollPanelLayout() {
* public void layoutContainer(Container p) {
* super.layoutContainer(p);
* // do some extra work here ...
* }
* };
* scrollpane.setLayout(mySPLayout):
* </pre>
*/
}
/**
* Removes an existing component. When a new component, such as
* the left corner, or vertical scrollbar, is added, the old one,
* if it exists, must be removed.
* <p>
* This method returns <code>newC</code>. If <code>oldC</code> is
* not equal to <code>newC</code> and is non-<code>null</code>,
* it will be removed from its parent.
*
* @param oldC the <code>Component</code> to replace
* @param newC the <code>Component</code> to add
* @return the <code>newC</code>
*/
{
}
return newC;
}
/**
* Adds the specified component to the layout. The layout is
* identified using one of:
* <ul>
* <li>ScrollPaneConstants.VIEWPORT
* <li>ScrollPaneConstants.VERTICAL_SCROLLBAR
* <li>ScrollPaneConstants.HORIZONTAL_SCROLLBAR
* <li>ScrollPaneConstants.ROW_HEADER
* <li>ScrollPaneConstants.COLUMN_HEADER
* <li>ScrollPaneConstants.LOWER_LEFT_CORNER
* <li>ScrollPaneConstants.LOWER_RIGHT_CORNER
* <li>ScrollPaneConstants.UPPER_LEFT_CORNER
* <li>ScrollPaneConstants.UPPER_RIGHT_CORNER
* </ul>
*
* @param s the component identifier
* @param c the the component to be added
* @exception IllegalArgumentException if <code>s</code> is an invalid key
*/
{
}
else if (s.equals(VERTICAL_SCROLLBAR)) {
}
else if (s.equals(HORIZONTAL_SCROLLBAR)) {
}
else if (s.equals(ROW_HEADER)) {
}
else if (s.equals(COLUMN_HEADER)) {
}
else if (s.equals(LOWER_LEFT_CORNER)) {
}
else if (s.equals(LOWER_RIGHT_CORNER)) {
}
else if (s.equals(UPPER_LEFT_CORNER)) {
}
else if (s.equals(UPPER_RIGHT_CORNER)) {
}
else {
throw new IllegalArgumentException("invalid layout key " + s);
}
}
/**
* Removes the specified component from the layout.
*
* @param c the component to remove
*/
{
if (c == viewport) {
}
else if (c == vsb) {
}
else if (c == hsb) {
}
else if (c == rowHead) {
}
else if (c == colHead) {
}
else if (c == lowerLeft) {
}
else if (c == lowerRight) {
lowerRight = null;
}
else if (c == upperLeft) {
}
else if (c == upperRight) {
upperRight = null;
}
}
/**
* Returns the vertical scrollbar-display policy.
*
* @return an integer giving the display policy
* @see #setVerticalScrollBarPolicy
*/
public int getVerticalScrollBarPolicy() {
return vsbPolicy;
}
/**
* Sets the vertical scrollbar-display policy. The options
* are:
* <ul>
* <li>ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED
* <li>ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER
* <li>ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS
* </ul>
* Note: Applications should use the <code>JScrollPane</code> version
* of this method. It only exists for backwards compatibility
* with the Swing 1.0.2 (and earlier) versions of this class.
*
* @param x an integer giving the display policy
* @exception IllegalArgumentException if <code>x</code> is an invalid
* vertical scroll bar policy, as listed above
*/
public void setVerticalScrollBarPolicy(int x) {
switch (x) {
case VERTICAL_SCROLLBAR_NEVER:
vsbPolicy = x;
break;
default:
throw new IllegalArgumentException("invalid verticalScrollBarPolicy");
}
}
/**
* Returns the horizontal scrollbar-display policy.
*
* @return an integer giving the display policy
* @see #setHorizontalScrollBarPolicy
*/
public int getHorizontalScrollBarPolicy() {
return hsbPolicy;
}
/**
* Sets the horizontal scrollbar-display policy.
* The options are:<ul>
* <li>ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED
* <li>ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER
* <li>ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS
* </ul>
* Note: Applications should use the <code>JScrollPane</code> version
* of this method. It only exists for backwards compatibility
* with the Swing 1.0.2 (and earlier) versions of this class.
*
* @param x an int giving the display policy
* @exception IllegalArgumentException if <code>x</code> is not a valid
* horizontal scrollbar policy, as listed above
*/
public void setHorizontalScrollBarPolicy(int x) {
switch (x) {
hsbPolicy = x;
break;
default:
throw new IllegalArgumentException("invalid horizontalScrollBarPolicy");
}
}
/**
* Returns the <code>JViewport</code> object that displays the
* scrollable contents.
* @return the <code>JViewport</code> object that displays the scrollable contents
* @see JScrollPane#getViewport
*/
return viewport;
}
/**
* Returns the <code>JScrollBar</code> object that handles horizontal scrolling.
* @return the <code>JScrollBar</code> object that handles horizontal scrolling
* @see JScrollPane#getHorizontalScrollBar
*/
return hsb;
}
/**
* Returns the <code>JScrollBar</code> object that handles vertical scrolling.
* @return the <code>JScrollBar</code> object that handles vertical scrolling
* @see JScrollPane#getVerticalScrollBar
*/
return vsb;
}
/**
* Returns the <code>JViewport</code> object that is the row header.
* @return the <code>JViewport</code> object that is the row header
* @see JScrollPane#getRowHeader
*/
return rowHead;
}
/**
* Returns the <code>JViewport</code> object that is the column header.
* @return the <code>JViewport</code> object that is the column header
* @see JScrollPane#getColumnHeader
*/
return colHead;
}
/**
* Returns the <code>Component</code> at the specified corner.
* @param key the <code>String</code> specifying the corner
* @return the <code>Component</code> at the specified corner, as defined in
* {@link ScrollPaneConstants}; if <code>key</code> is not one of the
* four corners, <code>null</code> is returned
* @see JScrollPane#getCorner
*/
return lowerLeft;
}
return lowerRight;
}
return upperLeft;
}
return upperRight;
}
else {
return null;
}
}
/**
* The preferred size of a <code>ScrollPane</code> is the size of the insets,
* plus the preferred size of the viewport, plus the preferred size of
* the visible headers, plus the preferred size of the scrollbars
* that will appear given the current view and the current
* scrollbar displayPolicies.
* <p>Note that the rowHeader is calculated as part of the preferred width
* and the colHeader is calculated as part of the preferred size.
*
* @param parent the <code>Container</code> that will be laid out
* @return a <code>Dimension</code> object specifying the preferred size of the
* viewport and any scrollbars
* @see ViewportLayout
* @see LayoutManager
*/
{
/* Sync the (now obsolete) policy fields with the
* JScrollPane.
*/
/* Note that viewport.getViewSize() is equivalent to
* viewport.getView().getPreferredSize() modulo a null
* view or a view whose size was explicitly set.
*/
} else {
}
}
/* If there's a viewport add its preferredSize.
*/
if (extentSize != null) {
}
/* If there's a JScrollPane.viewportBorder, add its insets.
*/
if (viewportBorder != null) {
}
/* If a header exists and it's visible, factor its
* preferred size in.
*/
}
}
/* If a scrollbar is going to appear, factor its preferred size in.
* If the scrollbars policy is AS_NEEDED, this can be a little
* tricky:
*
* - If the view is a Scrollable then scrollableTracksViewportWidth
* and scrollableTracksViewportHeight can be used to effectively
* disable scrolling (if they're true) in their respective dimensions.
*
* - Assuming that a scrollbar hasn't been disabled by the
* previous constraint, we need to decide if the scrollbar is going
* to appear to correctly compute the JScrollPanes preferred size.
* To do this we compare the preferredSize of the viewport (the
* extentSize) to the preferredSize of the view. Although we're
* not responsible for laying out the view we'll assume that the
* JViewport will always give it its preferredSize.
*/
if (vsbPolicy == VERTICAL_SCROLLBAR_ALWAYS) {
}
boolean canScroll = true;
if (view instanceof Scrollable) {
}
}
}
}
if (hsbPolicy == HORIZONTAL_SCROLLBAR_ALWAYS) {
}
boolean canScroll = true;
if (view instanceof Scrollable) {
}
}
}
}
}
/**
* The minimum size of a <code>ScrollPane</code> is the size of the insets
* plus minimum size of the viewport, plus the scrollpane's
* viewportBorder insets, plus the minimum size
* of the visible headers, plus the minimum size of the
* scrollbars whose displayPolicy isn't NEVER.
*
* @param parent the <code>Container</code> that will be laid out
* @return a <code>Dimension</code> object specifying the minimum size
*/
{
/* Sync the (now obsolete) policy fields with the
* JScrollPane.
*/
/* If there's a viewport add its minimumSize.
*/
}
/* If there's a JScrollPane.viewportBorder, add its insets.
*/
if (viewportBorder != null) {
}
/* If a header exists and it's visible, factor its
* minimum size in.
*/
}
}
/* If a scrollbar might appear, factor its minimum
* size in.
*/
}
}
}
/**
* Lays out the scrollpane. The positioning of components depends on
* the following constraints:
* <ul>
* <li> The row header, if present and visible, gets its preferred
* width and the viewport's height.
*
* <li> The column header, if present and visible, gets its preferred
* height and the viewport's width.
*
* <li> If a vertical scrollbar is needed, i.e. if the viewport's extent
* height is smaller than its view height or if the <code>displayPolicy</code>
* is ALWAYS, it's treated like the row header with respect to its
* dimensions and is made visible.
*
* <li> If a horizontal scrollbar is needed, it is treated like the
* column header (see the paragraph above regarding the vertical scrollbar).
*
* <li> If the scrollpane has a non-<code>null</code>
* <code>viewportBorder</code>, then space is allocated for that.
*
* <li> The viewport gets the space available after accounting for
* the previous constraints.
*
* <li> The corner components, if provided, are aligned with the
* ends of the scrollbars and headers. If there is a vertical
* scrollbar, the right corners appear; if there is a horizontal
* scrollbar, the lower corners appear; a row header gets left
* corners, and a column header gets upper corners.
* </ul>
*
* @param parent the <code>Container</code> to lay out
*/
{
/* Sync the (now obsolete) policy fields with the
* JScrollPane.
*/
/* Get the scrollPane's orientation.
*/
/* If there's a visible column header remove the space it
* needs from the top of availR. The column header is treated
* as if it were fixed height, arbitrary width.
*/
availR.y += colHeadHeight;
}
/* If there's a visible row header remove the space it needs
* from the left or right of availR. The row header is treated
* as if it were fixed width, arbitrary height.
*/
if ( leftToRight ) {
availR.x += rowHeadWidth;
} else {
}
}
/* If there's a JScrollPane.viewportBorder, remove the
* space it occupies for availR.
*/
if (viewportBorder != null) {
}
else {
}
/* At this point availR is the space available for the viewport
* and scrollbars. rowHeadR is correct except for its height and y
* and colHeadR is correct except for its width and x. Once we're
* through computing the dimensions of these three parts we can
* go back and set the dimensions of rowHeadR.height, rowHeadR.y,
* colHeadR.width, colHeadR.x and the bounds for the corners.
*
* We'll decide about putting up scrollbars by comparing the
* viewport views preferred size with the viewports extent
* size (generally just its size). Using the preferredSize is
* reasonable because layout proceeds top down - so we expect
* the viewport to be laid out next. And we assume that the
* viewports layout manager will give the view it's preferred
* size. One exception to this is when the view implements
* Scrollable and Scrollable.getViewTracksViewport{Width,Height}
* methods return true. If the view is tracking the viewports
* width we don't bother with a horizontal scrollbar, similarly
* if view.getViewTracksViewport(Height) is true we don't bother
* with a vertical scrollbar.
*/
boolean viewTracksViewportWidth = false;
boolean viewTracksViewportHeight = false;
// Don't bother checking the Scrollable methods if there is no room
// for the viewport, we aren't going to show any scrollbars in this
// case anyway.
}
else {
}
/* If there's a vertical scrollbar and we need one, allocate
* space for it (we'll make it visible later). A vertical
* scrollbar is considered to be fixed width, arbitrary height.
*/
boolean vsbNeeded;
if (isEmpty) {
vsbNeeded = false;
}
else if (vsbPolicy == VERTICAL_SCROLLBAR_ALWAYS) {
vsbNeeded = true;
}
else if (vsbPolicy == VERTICAL_SCROLLBAR_NEVER) {
vsbNeeded = false;
}
else { // vsbPolicy == VERTICAL_SCROLLBAR_AS_NEEDED
}
}
/* If there's a horizontal scrollbar and we need one, allocate
* space for it (we'll make it visible later). A horizontal
* scrollbar is considered to be fixed height, arbitrary width.
*/
boolean hsbNeeded;
if (isEmpty) {
hsbNeeded = false;
}
else if (hsbPolicy == HORIZONTAL_SCROLLBAR_ALWAYS) {
hsbNeeded = true;
}
else if (hsbPolicy == HORIZONTAL_SCROLLBAR_NEVER) {
hsbNeeded = false;
}
else { // hsbPolicy == HORIZONTAL_SCROLLBAR_AS_NEEDED
}
/* If we added the horizontal scrollbar then we've implicitly
* reduced the vertical space available to the viewport.
* As a consequence we may have to add the vertical scrollbar,
* if that hasn't been done so already. Of course we
* don't bother with any of this if the vsbPolicy is NEVER.
*/
(vsbPolicy != VERTICAL_SCROLLBAR_NEVER)) {
if (vsbNeeded) {
}
}
}
/* Set the size of the viewport first, and then recheck the Scrollable
* methods. Some components base their return values for the Scrollable
* methods on the size of the Viewport, so that if we don't
* ask after resetting the bounds we may have gotten the wrong
* answer.
*/
boolean oldHSBNeeded = hsbNeeded;
boolean oldVSBNeeded = vsbNeeded;
boolean newVSBNeeded = !viewTracksViewportHeight &&
if (newVSBNeeded != vsbNeeded) {
}
}
boolean newHSBbNeeded = !viewTracksViewportWidth &&
if (newHSBbNeeded != hsbNeeded) {
(vsbPolicy != VERTICAL_SCROLLBAR_NEVER)) {
if (vsbNeeded) {
}
}
}
}
if (oldHSBNeeded != hsbNeeded ||
oldVSBNeeded != vsbNeeded) {
// You could argue that we should recheck the
// Scrollable methods again until they stop changing,
// but they might never stop changing, so we stop here
// and don't do any additional checks.
}
}
}
/* We now have the final size of the viewport: availR.
*/
/* Set the bounds of the remaining components. The scrollbars
* are made invisible if they're not needed.
*/
}
}
if (vsbNeeded) {
{
{
// This is used primarily for GTK L&F, which needs to
// extend the vertical scrollbar to fill the upper
// corner near the column header. Note that we skip
// this step (and use the default behavior) if the
// user has set a custom corner component.
}
}
vsb.setVisible(true);
}
else {
vsb.setVisible(false);
}
}
if (hsbNeeded) {
{
{
// This is used primarily for GTK L&F, which needs to
// extend the horizontal scrollbar to fill the lower
// corner near the row header. Note that we skip
// this step (and use the default behavior) if the
// user has set a custom corner component.
if (leftToRight) {
}
}
}
hsb.setVisible(true);
}
else {
hsb.setVisible(false);
}
}
hsbR.y,
}
if (lowerRight != null) {
hsbR.y,
}
colHeadR.y,
}
if (upperRight != null) {
colHeadR.y,
}
}
/**
* Adjusts the <code>Rectangle</code> <code>available</code> based on if
* the vertical scrollbar is needed (<code>wantsVSB</code>).
* The location of the vsb is updated in <code>vsbR</code>, and
* the viewport border insets (<code>vpbInsets</code>) are used to offset
* the vsb. This is only called when <code>wantsVSB</code> has
* changed, eg you shouldn't invoke adjustForVSB(true) twice.
*/
boolean leftToRight) {
if (wantsVSB) {
if( leftToRight ) {
} else {
}
}
else {
}
}
/**
* Adjusts the <code>Rectangle</code> <code>available</code> based on if
* the horizontal scrollbar is needed (<code>wantsHSB</code>).
* The location of the hsb is updated in <code>hsbR</code>, and
* the viewport border insets (<code>vpbInsets</code>) are used to offset
* the hsb. This is only called when <code>wantsHSB</code> has
* changed, eg you shouldn't invoked adjustForHSB(true) twice.
*/
if (wantsHSB) {
}
else {
}
}
/**
* Returns the bounds of the border around the specified scroll pane's
* viewport.
*
* @return the size and position of the viewport border
* @deprecated As of JDK version Swing1.1
* replaced by <code>JScrollPane.getViewportBorderBounds()</code>.
*/
return scrollpane.getViewportBorderBounds();
}
/**
* The UI resource version of <code>ScrollPaneLayout</code>.
*/
}