edu.umd.cs.piccolox.swing.PScrollPaneLayout Maven / Gradle / Ivy
/*
* Copyright (c) 2008-2011, Piccolo2D project, http://piccolo2d.org
* Copyright (c) 1998-2008, University of Maryland
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided
* that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list of conditions
* and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions
* and the following disclaimer in the documentation and/or other materials provided with the
* distribution.
*
* None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
* contributors may be used to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package edu.umd.cs.piccolox.swing;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Rectangle;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneLayout;
import javax.swing.border.Border;
import edu.umd.cs.piccolo.util.PBounds;
/**
* A subclass of ScrollPaneLayout that looks at the Viewport for sizing
* information rather than View. Also queries the Viewport for sizing
* information after each decision about scrollbar visiblity.
*
* @author Lance Good
*/
public class PScrollPaneLayout extends ScrollPaneLayout {
private static final long serialVersionUID = 1L;
/**
* MODIFIED FROM javax.swing.ScrollPaneLayout.layoutContainer.
*
* This is largely the same as ScrollPaneLayout.layoutContainer but obtains
* the preferred view size from the viewport rather than directly from the
* view so the viewport can get the preferred size from the PScrollDirector
*
* @param parent the Container to lay out
*/
public void layoutContainer(final Container parent) {
// Sync the (now obsolete) policy fields with the JScrollPane.
if (!(parent instanceof JScrollPane)) {
throw new IllegalArgumentException("layoutContainer may only be applied to JScrollPanes");
}
final JScrollPane scrollPane = (JScrollPane) parent;
vsbPolicy = scrollPane.getVerticalScrollBarPolicy();
hsbPolicy = scrollPane.getHorizontalScrollBarPolicy();
final Rectangle availR = scrollPane.getBounds();
availR.setLocation(0, 0);
final Insets insets = parent.getInsets();
availR.x = insets.left;
availR.y = insets.top;
availR.width -= insets.left + insets.right;
availR.height -= insets.top + insets.bottom;
// Get the scrollPane's orientation.
final boolean leftToRight = scrollPane.getComponentOrientation().isLeftToRight();
/*
* 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.
*/
final Rectangle colHeadR = new Rectangle(0, availR.y, 0, 0);
if (colHead != null && colHead.isVisible()) {
final 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 or right of availR. The row header is treated as if it were
* fixed width, arbitrary height.
*/
final Rectangle rowHeadR = new Rectangle(0, 0, 0, 0);
if (rowHead != null && rowHead.isVisible()) {
final int rowHeadWidth = rowHead.getPreferredSize().width;
rowHeadR.width = rowHeadWidth;
availR.width -= rowHeadWidth;
if (leftToRight) {
rowHeadR.x = availR.x;
availR.x += rowHeadWidth;
}
else {
rowHeadR.x = availR.x + availR.width;
}
}
/*
* If there's a JScrollPane.viewportBorder, remove the space it occupies
* for availR.
*/
final Border viewportBorder = scrollPane.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);
}
/*
* 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 layed out next.
* And we assume that the viewports layout manager will give the view
* it's preferred size.
*/
Dimension extentSize = getExtentSize(availR);
final PBounds cameraBounds = new PBounds(0, 0, extentSize.getWidth(), extentSize.getHeight());
// LEG: Modification to ask the viewport for the view size rather
// than asking the view directly
Dimension viewPrefSize = getViewSize(cameraBounds);
/*
* 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.
*/
final Rectangle vsbR = new Rectangle(0, availR.y - vpbInsets.top, 0, 0);
boolean vsbNeeded;
if (vsbPolicy == VERTICAL_SCROLLBAR_ALWAYS) {
vsbNeeded = true;
}
else if (vsbPolicy == VERTICAL_SCROLLBAR_NEVER) {
vsbNeeded = false;
}
else { // vsbPolicy == VERTICAL_SCROLLBAR_AS_NEEDED
vsbNeeded = viewPrefSize.height > extentSize.height;
}
if (vsb != null && vsbNeeded) {
adjustForVSB(true, availR, vsbR, vpbInsets, leftToRight);
extentSize = viewport.toViewCoordinates(availR.getSize());
// LEG: Modification because the view's preferred size needs to
// be recomputed because the extent may have changed
cameraBounds.setRect(0, 0, extentSize.getWidth(), extentSize.getHeight());
viewPrefSize = ((PViewport) viewport).getViewSize(cameraBounds);
}
/*
* 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.
*/
final Rectangle hsbR = new Rectangle(availR.x - vpbInsets.left, 0, 0, 0);
boolean hsbNeeded;
if (hsbPolicy == HORIZONTAL_SCROLLBAR_ALWAYS) {
hsbNeeded = true;
}
else if (hsbPolicy == HORIZONTAL_SCROLLBAR_NEVER) {
hsbNeeded = false;
}
else { // hsbPolicy == HORIZONTAL_SCROLLBAR_AS_NEEDED
hsbNeeded = viewPrefSize.width > extentSize.width;
}
if (hsb != null && hsbNeeded) {
adjustForHSB(true, availR, hsbR, vpbInsets);
/*
* 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());
// LEG: Modification because the view's preferred size needs to
// be recomputed because the extent may have changed
cameraBounds.setRect(0, 0, extentSize.getWidth(), extentSize.getHeight());
viewPrefSize = ((PViewport) viewport).getViewSize(cameraBounds);
vsbNeeded = viewPrefSize.height > extentSize.height;
if (vsbNeeded) {
adjustForVSB(true, availR, vsbR, vpbInsets, leftToRight);
}
}
}
/*
* 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.
*/
if (viewport != null) {
viewport.setBounds(availR);
}
/*
* 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 + vpbInsets.top + vpbInsets.bottom;
rowHeadR.y = availR.y - vpbInsets.top;
colHeadR.width = availR.width + vpbInsets.left + vpbInsets.right;
colHeadR.x = availR.x - vpbInsets.left;
/*
* Set the bounds of the remaining components. The scrollbars are made
* invisible if they're not needed.
*/
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) {
if (leftToRight) {
lowerLeft.setBounds(rowHeadR.x, hsbR.y, rowHeadR.width, hsbR.height);
}
else {
lowerLeft.setBounds(vsbR.x, hsbR.y, vsbR.width, hsbR.height);
}
}
if (lowerRight != null) {
if (leftToRight) {
lowerRight.setBounds(vsbR.x, hsbR.y, vsbR.width, hsbR.height);
}
else {
lowerRight.setBounds(rowHeadR.x, hsbR.y, rowHeadR.width, hsbR.height);
}
}
if (upperLeft != null) {
if (leftToRight) {
upperLeft.setBounds(rowHeadR.x, colHeadR.y, rowHeadR.width, colHeadR.height);
}
else {
upperLeft.setBounds(vsbR.x, colHeadR.y, vsbR.width, colHeadR.height);
}
}
if (upperRight != null) {
if (leftToRight) {
upperRight.setBounds(vsbR.x, colHeadR.y, vsbR.width, colHeadR.height);
}
else {
upperRight.setBounds(rowHeadR.x, colHeadR.y, rowHeadR.width, colHeadR.height);
}
}
}
/**
* @param cameraBounds
* @return
*/
private Dimension getViewSize(final PBounds cameraBounds) {
Dimension viewPrefSize;
if (viewport != null) {
viewPrefSize = ((PViewport) viewport).getViewSize(cameraBounds);
}
else {
viewPrefSize = new Dimension(0, 0);
}
return viewPrefSize;
}
/**
* @param availR
* @return
*/
private Dimension getExtentSize(final Rectangle availR) {
Dimension extentSize;
if (viewport != null) {
extentSize = viewport.toViewCoordinates(availR.getSize());
}
else {
extentSize = new Dimension(0, 0);
}
return extentSize;
}
/**
* Copied FROM javax.swing.ScrollPaneLayout.adjustForVSB.
*
* This method is called from ScrollPaneLayout.layoutContainer and is
* private in ScrollPaneLayout so it was copied here
*
* @param wantsVSB whether to account for vertical scrollbar
* @param available region to adjust
* @param vsbR vertical scroll bar region
* @param vpbInsets margin of vertical scroll bars
* @param leftToRight orientation of the text LTR or RTL
*/
protected void adjustForVSB(final boolean wantsVSB, final Rectangle available, final Rectangle vsbR,
final Insets vpbInsets, final boolean leftToRight) {
final int vsbWidth = vsb.getPreferredSize().width;
if (wantsVSB) {
available.width -= vsbWidth;
vsbR.width = vsbWidth;
if (leftToRight) {
vsbR.x = available.x + available.width + vpbInsets.right;
}
else {
vsbR.x = available.x - vpbInsets.left;
available.x += vsbWidth;
}
}
else {
available.width += vsbWidth;
}
}
/**
* Copied FROM javax.swing.ScrollPaneLayout.adjustForHSB.
*
* This method is called from ScrollPaneLayout.layoutContainer and is
* private in ScrollPaneLayout so it was copied here
*
* @param wantsHSB whether to account for horizontal scrollbar
* @param available region to adjust
* @param hsbR vertical scroll bar region
* @param vpbInsets margin of the scroll bars
*/
protected void adjustForHSB(final boolean wantsHSB, final Rectangle available, final Rectangle hsbR,
final Insets vpbInsets) {
final int hsbHeight = hsb.getPreferredSize().height;
if (wantsHSB) {
available.height -= hsbHeight;
hsbR.y = available.y + available.height + vpbInsets.bottom;
hsbR.height = hsbHeight;
}
else {
available.height += hsbHeight;
}
}
/**
* The UI resource version of PScrollPaneLayout. It isn't clear why Swing
* does this in ScrollPaneLayout but we'll do it here too just to be safe.
*/
public static class UIResource extends PScrollPaneLayout implements javax.swing.plaf.UIResource {
/**
*
*/
private static final long serialVersionUID = 1L;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy