home *** CD-ROM | disk | FTP | other *** search
Java Source | 1998-03-20 | 20.2 KB | 685 lines |
- /*
- * @(#)ScrollPaneLayout.java 1.20 98/02/02
- *
- * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
- *
- * This software is the confidential and proprietary information of Sun
- * Microsystems, Inc. ("Confidential Information"). You shall not
- * disclose such Confidential Information and shall use it only in
- * accordance with the terms of the license agreement you entered into
- * with Sun.
- *
- * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
- * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
- * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
- * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
- * THIS SOFTWARE OR ITS DERIVATIVES.
- *
- */
-
- package java.awt.swing;
-
-
- import java.awt.swing.border.*;
-
- import java.awt.LayoutManager;
- import java.awt.Component;
- import java.awt.Container;
- import java.awt.Rectangle;
- import java.awt.Dimension;
- import java.awt.Insets;
- import java.io.Serializable;
-
-
- /**
- * The layout manager used by JScrollPane. JScrollPaneLayout is
- * responsible for nine components: a viewport, two scrollbars,
- * a row header, a column header, and four "corner" components.
- * <p>
- * 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 Swing1.0 applications. It will
- * not be possible to load serialized Swing1.0 objects with future releases
- * of Swing. The JDK1.2 release of Swing will be the compatibility
- * baseline for the serialized form of Swing objects.
- *
- * @version 1.20 02/02/98
- * @author unknown
- */
- public class ScrollPaneLayout
- implements LayoutManager, ScrollPaneConstants, Serializable
- {
- protected JViewport viewport;
- protected JScrollBar vsb;
- protected JScrollBar hsb;
- protected JViewport rowHead;
- protected JViewport colHead;
- protected Component lowerLeft;
- protected Component lowerRight;
- protected Component upperLeft;
- protected Component upperRight;
-
- protected int vsbPolicy = VERTICAL_SCROLLBAR_AS_NEEDED;
- protected int hsbPolicy = HORIZONTAL_SCROLLBAR_AS_NEEDED;
-
-
- /**
- * Only one of these is allowed, remove the old one if neccessary.
- */
- protected Component addSingletonComponent(Component oldC, Component newC)
- {
- if ((oldC != null) && (oldC != newC)) {
- oldC.getParent().remove(oldC);
- }
- return newC;
- }
-
-
- public void addLayoutComponent(String s, Component c)
- {
- if (s.equals(VIEWPORT)) {
- viewport = (JViewport)addSingletonComponent(viewport, c);
- }
- else if (s.equals(VERTICAL_SCROLLBAR)) {
- vsb = (JScrollBar)addSingletonComponent(vsb, c);
- }
- else if (s.equals(HORIZONTAL_SCROLLBAR)) {
- hsb = (JScrollBar)addSingletonComponent(hsb, c);
- }
- else if (s.equals(ROW_HEADER)) {
- rowHead = (JViewport)addSingletonComponent(rowHead, c);
- }
- else if (s.equals(COLUMN_HEADER)) {
- colHead = (JViewport)addSingletonComponent(colHead, c);
- }
- else if (s.equals(LOWER_LEFT_CORNER)) {
- lowerLeft = addSingletonComponent(lowerLeft, c);
- }
- else if (s.equals(LOWER_RIGHT_CORNER)) {
- lowerRight = addSingletonComponent(lowerRight, c);
- }
- else if (s.equals(UPPER_LEFT_CORNER)) {
- upperLeft = addSingletonComponent(upperLeft, c);
- }
- else if (s.equals(UPPER_RIGHT_CORNER)) {
- upperRight = addSingletonComponent(upperRight, c);
- }
- else {
- throw new IllegalArgumentException("invalid layout key " + s);
- }
- }
-
-
- public void removeLayoutComponent(Component c)
- {
- if (c == viewport) {
- viewport = null;
- }
- else if (c == vsb) {
- vsb = null;
- }
- else if (c == hsb) {
- hsb = null;
- }
- else if (c == rowHead) {
- rowHead = null;
- }
- else if (c == colHead) {
- colHead = null;
- }
- else if (c == lowerLeft) {
- lowerLeft = null;
- }
- else if (c == upperLeft) {
- upperLeft = null;
- }
- else if (c == upperRight) {
- upperRight = null;
- }
- }
-
-
- public int getVerticalScrollBarPolicy() {
- return vsbPolicy;
- }
-
- public void setVerticalScrollBarPolicy(int x) {
- switch (x) {
- case VERTICAL_SCROLLBAR_AS_NEEDED:
- case VERTICAL_SCROLLBAR_NEVER:
- case VERTICAL_SCROLLBAR_ALWAYS:
- vsbPolicy = x;
- break;
- default:
- throw new IllegalArgumentException("invalid verticalScrollBarPolicy");
- }
- }
-
-
- public int getHorizontalScrollBarPolicy() {
- return hsbPolicy;
- }
-
- public void setHorizontalScrollBarPolicy(int x) {
- switch (x) {
- case HORIZONTAL_SCROLLBAR_AS_NEEDED:
- case HORIZONTAL_SCROLLBAR_NEVER:
- case HORIZONTAL_SCROLLBAR_ALWAYS:
- hsbPolicy = x;
- break;
- default:
- throw new IllegalArgumentException("invalid horizontalScrollBarPolicy");
- }
- }
-
-
- public JViewport getViewport() {
- return viewport;
- }
-
-
- public JScrollBar getHorizontalScrollBar() {
- return hsb;
- }
-
- public JScrollBar getVerticalScrollBar() {
- return vsb;
- }
-
-
- public JViewport getRowHeader() {
- return rowHead;
- }
-
- public JViewport getColumnHeader() {
- return colHead;
- }
-
-
- public Component getCorner(String key) {
- 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;
- }
- }
-
-
- /**
- * The preferred size of a ScrollPane is the size of the insets
- * plus 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.
- *
- * @return The preferred size of the viewport and any scrollbars.
- * @see ViewportLayout
- * @see LayoutManager
- */
-
- public Dimension preferredLayoutSize(Container parent)
- {
- Insets insets = parent.getInsets();
- int prefWidth = insets.left + insets.right;
- int prefHeight = insets.top + insets.bottom;
-
- /* Note that viewport.getViewSize() is equivalent to
- * viewport.getView().getPreferredSize() modulo a null
- * view or a view whose size was explicitly set.
- */
-
- Dimension extentSize = null;
- Dimension viewSize = null;
- Component view = null;
-
- if (viewport != null) {
- extentSize = viewport.getPreferredSize();
- viewSize = viewport.getViewSize();
- view = viewport.getView();
- }
-
- /* If there's a viewport add its preferredSize.
- */
-
- if (extentSize != null) {
- prefWidth += extentSize.width;
- prefHeight += extentSize.height;
- }
-
- /* If there's a JScrollPane.viewportBorder, add its insets.
- */
-
- Border viewportBorder = ((JScrollPane)parent).getViewportBorder();
- if (viewportBorder != null) {
- Insets vpbInsets = viewportBorder.getBorderInsets(parent);
- prefWidth += vpbInsets.left + vpbInsets.right;
- prefHeight += vpbInsets.top + vpbInsets.bottom;
- }
-
- /* If a header exists and it's visible, factor its
- * preferred size in.
- */
-
- if ((rowHead != null) && rowHead.isVisible()) {
- prefWidth += rowHead.getPreferredSize().width;
- }
-
- if ((colHead != null) && colHead.isVisible()) {
- prefHeight += colHead.getPreferredSize().height;
- }
-
- /* 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 ((vsb != null) && (vsbPolicy != VERTICAL_SCROLLBAR_NEVER)) {
- if (vsbPolicy == VERTICAL_SCROLLBAR_ALWAYS) {
- prefWidth += vsb.getPreferredSize().width;
- }
- else if ((viewSize != null) && (extentSize != null)) {
- boolean canScroll = true;
- if (view instanceof Scrollable) {
- canScroll = !((Scrollable)view).getScrollableTracksViewportHeight();
- }
- if (canScroll && (viewSize.height > extentSize.height)) {
- prefWidth += vsb.getPreferredSize().width;
- }
- }
- }
-
- if ((hsb != null) && (hsbPolicy != HORIZONTAL_SCROLLBAR_NEVER)) {
- if (hsbPolicy == HORIZONTAL_SCROLLBAR_ALWAYS) {
- prefHeight += hsb.getPreferredSize().height;
- }
- else if ((viewSize != null) && (extentSize != null)) {
- boolean canScroll = true;
- if (view instanceof Scrollable) {
- canScroll = !((Scrollable)view).getScrollableTracksViewportWidth();
- }
- if (canScroll && (viewSize.width > extentSize.width)) {
- prefHeight += hsb.getPreferredSize().height;
- }
- }
- }
-
- return new Dimension(prefWidth, prefHeight);
- }
-
-
- /**
- * The minimum size of a ScrollPane is the size of the insets
- * plus minimum size of the viewport, plus the scrollpanes
- * viewportBorder insets, plus the minimum size
- * of the visible headers, plus the minimum size of the
- * scrollbars whose displayPolicy isn't NEVER.
- */
-
- public Dimension minimumLayoutSize(Container parent)
- {
- Insets insets = parent.getInsets();
- int minWidth = insets.left + insets.right;
- int minHeight = insets.top + insets.bottom;
-
- /* If there's a viewport add its minimumSize.
- */
-
- if (viewport != null) {
- Dimension size = viewport.getMinimumSize();
- minWidth += size.width;
- minHeight += size.height;
- }
-
- /* If there's a JScrollPane.viewportBorder, add its insets.
- */
-
- Border viewportBorder = ((JScrollPane)parent).getViewportBorder();
- if (viewportBorder != null) {
- Insets vpbInsets = viewportBorder.getBorderInsets(parent);
- minWidth += vpbInsets.left + vpbInsets.right;
- minHeight += vpbInsets.top + vpbInsets.bottom;
- }
-
- /* If a header exists and it's visible, factor its
- * minimum size in.
- */
-
- if ((rowHead != null) && rowHead.isVisible()) {
- Dimension size = rowHead.getMinimumSize();
- minWidth += size.width;
- minHeight = Math.max(minHeight, size.height);
- }
-
- if ((colHead != null) && colHead.isVisible()) {
- Dimension size = colHead.getMinimumSize();
- minWidth = Math.max(minWidth, size.width);
- minHeight += size.height;
- }
-
- /* If a scrollbar might appear, factor its minimum
- * size in.
- */
-
- if ((vsb != null) && (vsbPolicy != VERTICAL_SCROLLBAR_NEVER)) {
- Dimension size = vsb.getMinimumSize();
- minWidth += size.width;
- minHeight = Math.max(minHeight, size.height);
- }
-
- if ((hsb != null) && (hsbPolicy != VERTICAL_SCROLLBAR_NEVER)) {
- Dimension size = hsb.getMinimumSize();
- minWidth = Math.max(minWidth, size.width);
- minHeight += size.height;
- }
-
- return new Dimension(minWidth, minHeight);
- }
-
-
- /**
- * Layout the scrollpane according to the following constraints:
- * <ul>
- * <li> The row header, if present and visible, gets its preferred
- * height and the viewports width.
- *
- * <li> The column header, if present and visible, gets its preferred
- * width and the viewports height.
- *
- * <li> If a vertical scrollbar is needed, i.e. if the viewports extent
- * height is smaller than its view height or if the displayPolicy
- * is ALWAYS, it's treated like the row header wrt it's dimensions and
- * it's made visible.
- *
- * <li> If a horizontal scrollbar is needed it's treated like the
- * column header (and see the vertical scrollbar item).
- *
- * <li> If the scrollpane has a non-null viewportBorder, 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's a vertical
- * scrollbar the right corners appear, if there's a horizontal
- * scrollbar the lower corners appear, a row header gets left
- * corners and a column header gets upper corners.
- * </ul>
- */
-
- public void layoutContainer(Container parent)
- {
- Rectangle availR = new Rectangle(parent.getSize());
-
- Insets insets = parent.getInsets();
- availR.x = insets.left;
- availR.y = insets.top;
- availR.width -= insets.left + insets.right;
- availR.height -= insets.top + insets.bottom;
-
-
- /* 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.
- */
-
- Rectangle colHeadR = new Rectangle(0, availR.y, 0, 0);
-
- if ((colHead != null) && (colHead.isVisible())) {
- int colHeadHeight = colHead.getPreferredSize().height;
- colHeadR.height = colHeadHeight;
- availR.y += colHeadHeight;
- availR.height -= colHeadHeight;
- }
-
- /* If there's a visible row header remove the space it needs
- * from the left of availR. The row header is treated
- * as if it were fixed width, arbitrary height.
- */
-
- Rectangle rowHeadR = new Rectangle(availR.x, 0, 0, 0);
-
- if ((rowHead != null) && (rowHead.isVisible())) {
- int rowHeadWidth = rowHead.getPreferredSize().width;
- rowHeadR.width = rowHeadWidth;
- availR.x += rowHeadWidth;
- availR.width -= rowHeadWidth;
- }
-
- /* If there's a JScrollPane.viewportBorder, remove the
- * space it occupies for availR.
- */
-
- Border viewportBorder = ((JScrollPane)parent).getViewportBorder();
- Insets vpbInsets;
- if (viewportBorder != null) {
- vpbInsets = viewportBorder.getBorderInsets(parent);
- availR.x += vpbInsets.left;
- availR.y += vpbInsets.top;
- availR.width -= vpbInsets.left + vpbInsets.right;
- availR.height -= vpbInsets.top + vpbInsets.bottom;
- }
- else {
- vpbInsets = new Insets(0,0,0,0);
- }
-
- colHeadR.x = availR.x;
- rowHeadR.y = availR.y;
-
- /* At this point availR is the space available for the viewport
- * and scrollbars and the rowHeadR colHeadR rectangles are correct
- * except for their width and height respectively. Once we're
- * through computing the dimensions of these three parts we can
- * go back and set the dimensions of rowHeadR.width, colHeadR.height,
- * 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 layed out next. And it will change the
- * resize the view to its preferred size or bigger. It's potentially
- * bigger if the views Scrollable.getViewTracksViewport{Width,Height}
- * returns true.
- */
-
- Component view = (viewport != null) ? viewport.getView() : null;
- Dimension viewSize =
- (view != null) ? view.getPreferredSize()
- : new Dimension(0,0);
-
- Dimension extentSize =
- (viewport != null) ? viewport.toViewCoordinates(availR.getSize())
- : new Dimension(0,0);
-
- /* 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.
- */
-
- Rectangle vsbR = new Rectangle(0, availR.y - vpbInsets.top, 0, 0);
- boolean vsbNeeded =
- (vsbPolicy == VERTICAL_SCROLLBAR_ALWAYS) ||
- ((viewSize.height > extentSize.height) &&
- (vsbPolicy == VERTICAL_SCROLLBAR_AS_NEEDED));
-
- if ((vsb != null) && vsbNeeded) {
- int vsbWidth = vsb.getPreferredSize().width;
- availR.width -= vsbWidth;
- vsbR.x = availR.x + availR.width + vpbInsets.right;
- vsbR.width = vsbWidth;
- }
-
- /* 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.
- */
-
- Rectangle hsbR = new Rectangle(availR.x - vpbInsets.left, 0, 0, 0);
- boolean hsbNeeded =
- (hsbPolicy == HORIZONTAL_SCROLLBAR_ALWAYS) ||
- ((viewSize.width > extentSize.width) &&
- (hsbPolicy == HORIZONTAL_SCROLLBAR_AS_NEEDED));
-
- if ((hsb != null) && hsbNeeded) {
- int hsbHeight = hsb.getPreferredSize().height;
- availR.height -= hsbHeight;
- hsbR.y = availR.y + availR.height + vpbInsets.bottom;
- hsbR.height = hsbHeight;
-
- /* 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. Ofcourse we
- * don't bother with any of this if the vsbPolicy is NEVER.
- */
- if ((vsb != null) && !vsbNeeded && (vsbPolicy != VERTICAL_SCROLLBAR_NEVER)) {
- extentSize = viewport.toViewCoordinates(availR.getSize());
- vsbNeeded = viewSize.height > extentSize.height;
-
- if (vsbNeeded) {
- int vsbWidth = vsb.getPreferredSize().width;
- availR.width -= vsbWidth;
- vsbR.x = availR.x + availR.width + vpbInsets.right;
- vsbR.width = vsbWidth;
- }
- }
- }
-
- /* We now have the final size of the viewport: availR.
- * Now fixup the header and scrollbar widths/heights.
- */
-
- vsbR.height = availR.height + vpbInsets.top + vpbInsets.bottom;
- hsbR.width = availR.width + vpbInsets.left + vpbInsets.right;
- rowHeadR.height = availR.height;
- colHeadR.width = availR.width;
-
- /* Set the bounds of all nine components. The scrollbars
- * are made invisible if they're not needed.
- */
-
- if (viewport != null) {
- viewport.setBounds(availR);
- }
-
- if (rowHead != null) {
- rowHead.setBounds(rowHeadR);
- }
-
- if (colHead != null) {
- colHead.setBounds(colHeadR);
- }
-
- if (vsb != null) {
- if (vsbNeeded) {
- vsb.setVisible(true);
- vsb.setBounds(vsbR);
- }
- else {
- vsb.setVisible(false);
- }
- }
-
- if (hsb != null) {
- if (hsbNeeded) {
- hsb.setVisible(true);
- hsb.setBounds(hsbR);
- }
- else {
- hsb.setVisible(false);
- }
- }
-
- if (lowerLeft != null) {
- lowerLeft.setBounds(rowHeadR.x, hsbR.y, rowHeadR.width, hsbR.height);
- }
-
- if (lowerRight != null) {
- lowerRight.setBounds(vsbR.x, hsbR.y, vsbR.width, hsbR.height);
- }
-
- if (upperLeft != null) {
- upperLeft.setBounds(rowHeadR.x, colHeadR.y, rowHeadR.width, colHeadR.height);
- }
-
- if (upperRight != null) {
- upperRight.setBounds(vsbR.x, colHeadR.y, vsbR.width, colHeadR.height);
- }
- }
-
-
- public Rectangle getViewportBorderBounds(JScrollPane sp)
- {
- Rectangle borderR = new Rectangle(sp.getSize());
-
- Insets insets = sp.getInsets();
- borderR.x = insets.left;
- borderR.y = insets.top;
- borderR.width -= insets.left + insets.right;
- borderR.height -= insets.top + insets.bottom;
-
-
- /* If there's a visible column header remove the space it
- * needs from the top of borderR.
- */
-
- 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.
- */
-
- if ((rowHead != null) && (rowHead.isVisible())) {
- int rowHeadWidth = rowHead.getWidth();
- borderR.x += rowHeadWidth;
- borderR.width -= rowHeadWidth;
- }
-
- /* If there's a visible vertical scrollbar remove the space it needs
- * from the width of borderR.
- */
-
- if ((vsb != null) && (vsb.isVisible())) {
- borderR.width -= vsb.getWidth();
- }
-
- /* If there's a visible horizontal scrollbar remove the space it needs
- * from the height of borderR.
- */
-
- if ((hsb != null) && (hsb.isVisible())) {
- borderR.height -= hsb.getHeight();
- }
-
- return borderR;
- }
- }
-