1: /* ScrollPaneLayout.java -- 2: Copyright (C) 2002, 2004 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package javax.swing; 40: 41: import java.awt.Component; 42: import java.awt.Container; 43: import java.awt.Dimension; 44: import java.awt.Insets; 45: import java.awt.LayoutManager; 46: import java.awt.Rectangle; 47: import java.io.Serializable; 48: 49: import javax.swing.border.Border; 50: 51: /** 52: * ScrollPaneLayout 53: * @author Andrew Selkirk 54: * @version 1.0 55: */ 56: public class ScrollPaneLayout 57: implements LayoutManager, ScrollPaneConstants, Serializable 58: { 59: private static final long serialVersionUID = -4480022884523193743L; 60: 61: public static class UIResource extends ScrollPaneLayout 62: implements javax.swing.plaf.UIResource 63: { 64: public UIResource() 65: { 66: super(); 67: } 68: } 69: 70: protected JViewport viewport; 71: protected JScrollBar vsb; 72: protected JScrollBar hsb; 73: protected JViewport rowHead; 74: protected JViewport colHead; 75: protected Component lowerLeft; 76: protected Component lowerRight; 77: protected Component upperLeft; 78: protected Component upperRight; 79: protected int vsbPolicy; 80: protected int hsbPolicy; 81: 82: public ScrollPaneLayout() 83: { 84: // Nothing to do here. 85: } 86: 87: public void syncWithScrollPane(JScrollPane scrollPane) 88: { 89: viewport = scrollPane.getViewport(); 90: rowHead = scrollPane.getRowHeader(); 91: colHead = scrollPane.getColumnHeader(); 92: vsb = scrollPane.getVerticalScrollBar(); 93: hsb = scrollPane.getHorizontalScrollBar(); 94: vsbPolicy = scrollPane.getVerticalScrollBarPolicy(); 95: hsbPolicy = scrollPane.getHorizontalScrollBarPolicy(); 96: lowerLeft = scrollPane.getCorner(LOWER_LEFT_CORNER); 97: lowerRight = scrollPane.getCorner(LOWER_RIGHT_CORNER); 98: upperLeft = scrollPane.getCorner(UPPER_LEFT_CORNER); 99: upperRight = scrollPane.getCorner(UPPER_RIGHT_CORNER); 100: } 101: 102: /** 103: * Removes an existing component. If oldComponent is not null 104: * and is not equal to newComponent, oldComponent must be removed 105: * from its parent. 106: * @param oldComponent the old Component that may need to be removed. 107: * @param newComponent the Component to add. 108: * @return the newComponent 109: */ 110: protected Component addSingletonComponent(Component oldComponent, 111: Component newComponent) 112: { 113: if (oldComponent != null && oldComponent != newComponent) 114: oldComponent.getParent().remove(oldComponent); 115: return newComponent; 116: } 117: 118: /** 119: * Add the specified component to the layout. 120: * @param key must be one of VIEWPORT, VERTICAL_SCROLLBAR, 121: * HORIZONTAL_SCROLLBAR, ROW_HEADER, COLUMN_HEADER, 122: * LOWER_RIGHT_CORNER, LOWER_LEFT_CORNER, UPPER_RIGHT_CORNER, 123: * UPPER_LEFT_CORNER. 124: * @param component the Component to add 125: * @throws IllegalArgumentException if key is not as above 126: */ 127: public void addLayoutComponent(String key, Component component) 128: { 129: if (key == VIEWPORT) 130: viewport = (JViewport) component; 131: else if (key == VERTICAL_SCROLLBAR) 132: vsb = (JScrollBar) component; 133: else if (key == HORIZONTAL_SCROLLBAR) 134: hsb = (JScrollBar) component; 135: else if (key == ROW_HEADER) 136: rowHead = (JViewport) component; 137: else if (key == COLUMN_HEADER) 138: colHead = (JViewport) component; 139: else if (key == LOWER_RIGHT_CORNER) 140: lowerRight = component; 141: else if (key == UPPER_RIGHT_CORNER) 142: upperRight = component; 143: else if (key == LOWER_LEFT_CORNER) 144: lowerLeft = component; 145: else if (key == UPPER_LEFT_CORNER) 146: upperLeft = component; 147: else 148: throw new IllegalArgumentException(); 149: } 150: 151: public void removeLayoutComponent(Component component) 152: { 153: if (component == viewport) 154: viewport = null; 155: else if (component == vsb) 156: vsb = null; 157: else if (component == hsb) 158: hsb = null; 159: else if (component == rowHead) 160: rowHead = null; 161: else if (component == colHead) 162: colHead = null; 163: else if (component == lowerRight) 164: lowerRight = null; 165: else if (component == upperRight) 166: upperRight = null; 167: else if (component == lowerLeft) 168: lowerLeft = null; 169: else if (component == upperLeft) 170: upperLeft = null; 171: } 172: 173: public int getVerticalScrollBarPolicy() 174: { 175: return vsbPolicy; 176: } 177: 178: /** 179: * Sets the vertical scrollbar policy. 180: * @param policy must be one of VERTICAL_SCROLLBAR_AS_NEEDED, 181: * VERTICAL_SCROLLBAR_NEVER, VERTICAL_SCROLLBAR_ALWAYS. 182: * @throws IllegalArgumentException if policy is not one of the valid 183: * JScrollBar policies. 184: */ 185: public void setVerticalScrollBarPolicy(int policy) 186: { 187: if (policy != VERTICAL_SCROLLBAR_AS_NEEDED && 188: policy != VERTICAL_SCROLLBAR_NEVER && 189: policy != VERTICAL_SCROLLBAR_ALWAYS) 190: throw new IllegalArgumentException("Illegal Scrollbar Policy"); 191: vsbPolicy = policy; 192: } 193: 194: public int getHorizontalScrollBarPolicy() 195: { 196: return hsbPolicy; 197: } 198: 199: /** 200: * Sets the horizontal scrollbar policy. 201: * @param policy must be one of HORIZONTAL_SCROLLBAR_AS_NEEDED, 202: * HORIZONTAL_SCROLLBAR_NEVER, HORIZONTAL_SCROLLBAR_ALWAYS. 203: * @throws IllegalArgumentException if policy is not one of the valid 204: * JScrollbar policies. 205: */ 206: public void setHorizontalScrollBarPolicy(int policy) 207: { 208: if (policy != HORIZONTAL_SCROLLBAR_AS_NEEDED && 209: policy != HORIZONTAL_SCROLLBAR_NEVER && 210: policy != HORIZONTAL_SCROLLBAR_ALWAYS) 211: throw new IllegalArgumentException("Illegal Scrollbar Policy"); 212: hsbPolicy = policy; 213: } 214: 215: public JViewport getViewport() 216: { 217: return viewport; 218: } 219: 220: public JScrollBar getHorizontalScrollBar() 221: { 222: return hsb; 223: } 224: 225: public JScrollBar getVerticalScrollBar() 226: { 227: return vsb; 228: } 229: 230: public JViewport getRowHeader() 231: { 232: return rowHead; 233: } 234: 235: public JViewport getColumnHeader() 236: { 237: return colHead; 238: } 239: 240: /** 241: * Returns the Component at the specified corner. 242: * @param key the corner. 243: * @return the Component at the specified corner, or null if 244: * key is not one of the four valid corners. 245: */ 246: public Component getCorner(String key) 247: { 248: if (key == LOWER_RIGHT_CORNER) 249: return lowerRight; 250: else if (key == UPPER_RIGHT_CORNER) 251: return upperRight; 252: else if (key == LOWER_LEFT_CORNER) 253: return lowerLeft; 254: else if (key == UPPER_LEFT_CORNER) 255: return upperLeft; 256: return null; 257: } 258: 259: public Dimension preferredLayoutSize(Container parent) 260: { 261: // Sun's implementation simply throws a ClassCastException if 262: // parent is no JScrollPane, so do we. 263: JScrollPane sc = (JScrollPane) parent; 264: Dimension viewportSize = viewport.getPreferredSize(); 265: Dimension viewSize = viewport.getViewSize(); 266: int width = viewportSize.width; 267: int height = viewportSize.height; 268: 269: // horizontal scrollbar needed if the view's preferred width 270: // is larger than the viewport's preferred width 271: if (hsb != null && viewSize.width > viewportSize.width) 272: height += hsb.getPreferredSize().height; 273: 274: // vertical scrollbar needed if the view's preferred height 275: // is larger than the viewport's preferred height 276: if (vsb != null && viewSize.height > viewportSize.height) 277: width += vsb.getPreferredSize().width; 278: if (rowHead != null && rowHead.isVisible()) 279: width += rowHead.getPreferredSize().width; 280: if (colHead != null && colHead.isVisible()) 281: height += colHead.getPreferredSize().height; 282: 283: // Add insets of viewportBorder if present. 284: Border vpBorder = sc.getViewportBorder(); 285: if (vpBorder != null) 286: { 287: Insets i = vpBorder.getBorderInsets(sc); 288: width += i.left + i.right; 289: height += i.top + i.bottom; 290: } 291: 292: Insets i = sc.getInsets(); 293: return new Dimension(width + i.left + i.right, 294: height + i.left + i.right); 295: } 296: 297: public Dimension minimumLayoutSize(Container parent) 298: { 299: // Sun's implementation simply throws a ClassCastException if 300: // parent is no JScrollPane, so do we. 301: JScrollPane sc = (JScrollPane) parent; 302: Insets i = sc.getInsets(); 303: Dimension viewportMinSize = sc.getViewport().getMinimumSize(); 304: 305: int width = i.left + i.right + viewportMinSize.width; 306: if (sc.getVerticalScrollBarPolicy() 307: != JScrollPane.VERTICAL_SCROLLBAR_NEVER) 308: width += sc.getVerticalScrollBar().getMinimumSize().width; 309: 310: int height = i.top + i.bottom + viewportMinSize.height; 311: if (sc.getHorizontalScrollBarPolicy() 312: != JScrollPane.HORIZONTAL_SCROLLBAR_NEVER) 313: height += sc.getHorizontalScrollBar().getMinimumSize().height; 314: 315: // Add insets of viewportBorder if present. 316: Border vpBorder = sc.getViewportBorder(); 317: if (vpBorder != null) 318: { 319: i = vpBorder.getBorderInsets(sc); 320: width += i.left + i.right; 321: height += i.top + i.bottom; 322: } 323: 324: return new Dimension(width, height); 325: } 326: 327: /** 328: * 329: * +----+--------------------+----+ y1 330: * | c1 | column header | c2 | 331: * +----+--------------------+----+ y2 332: * | r | | v | 333: * | o | | | 334: * | w | | s | 335: * | | | r | 336: * | h | | o | 337: * | e | viewport | l | 338: * | a | | l | 339: * | d | | b | 340: * | e | | a | 341: * | r | | r | 342: * +----+--------------------+----+ y3 343: * | c3 | h scrollbar | c4 | 344: * +----+--------------------+----+ y4 345: * x1 x2 x3 x4 346: * 347: */ 348: public void layoutContainer(Container parent) 349: { 350: // Sun's implementation simply throws a ClassCastException if 351: // parent is no JScrollPane, so do we. 352: JScrollPane sc = (JScrollPane) parent; 353: JViewport viewport = sc.getViewport(); 354: Component view = viewport.getView(); 355: 356: // If there is no view in the viewport, there is no work to be done. 357: if (view == null) 358: return; 359: 360: Dimension viewSize = viewport.getView().getPreferredSize(); 361: 362: int x1 = 0, x2 = 0, x3 = 0, x4 = 0; 363: int y1 = 0, y2 = 0, y3 = 0, y4 = 0; 364: Rectangle scrollPaneBounds = SwingUtilities.calculateInnerArea(sc, null); 365: 366: // If there is a viewportBorder, remove its insets from the available 367: // space. 368: Border vpBorder = sc.getViewportBorder(); 369: Insets vpi; 370: if (vpBorder != null) 371: vpi = vpBorder.getBorderInsets(sc); 372: else 373: vpi = new Insets(0, 0, 0, 0); 374: 375: x1 = scrollPaneBounds.x; 376: y1 = scrollPaneBounds.y; 377: x4 = scrollPaneBounds.x + scrollPaneBounds.width; 378: y4 = scrollPaneBounds.y + scrollPaneBounds.height; 379: if (colHead != null) 380: y2 = y1 + colHead.getPreferredSize().height; 381: else 382: y2 = y1; 383: 384: if (rowHead != null) 385: x2 = x1 + rowHead.getPreferredSize().width; 386: else 387: x2 = x1; 388: 389: int vsbPolicy = sc.getVerticalScrollBarPolicy(); 390: int hsbPolicy = sc.getHorizontalScrollBarPolicy(); 391: 392: int vsWidth = 0; 393: int hsHeight = 0; 394: 395: boolean showVsb = 396: (vsb != null) 397: && ((vsbPolicy == VERTICAL_SCROLLBAR_ALWAYS) 398: || (vsbPolicy == VERTICAL_SCROLLBAR_AS_NEEDED 399: && viewSize.height > (y4 - y2))); 400: 401: if (showVsb) 402: vsWidth = vsb.getPreferredSize().width; 403: 404: // The horizontal scroll bar may become necessary if the vertical scroll 405: // bar appears, reducing the space, left for the component. 406: 407: boolean showHsb = 408: (hsb != null) 409: && ((hsbPolicy == HORIZONTAL_SCROLLBAR_ALWAYS) 410: || (hsbPolicy == HORIZONTAL_SCROLLBAR_AS_NEEDED 411: && viewSize.width > (x4 - x2 - vsWidth))); 412: 413: if (showHsb) 414: hsHeight = hsb.getPreferredSize().height; 415: 416: // If the horizontal scroll bar appears, and the vertical scroll bar 417: // was not necessary assuming that there is no horizontal scroll bar, 418: // the vertical scroll bar may become necessary because the horizontal 419: // scroll bar reduces the vertical space for the component. 420: if (!showVsb) 421: { 422: showVsb = 423: (vsb != null) 424: && ((vsbPolicy == VERTICAL_SCROLLBAR_ALWAYS) 425: || (vsbPolicy == VERTICAL_SCROLLBAR_AS_NEEDED 426: && viewSize.height > (y4 - y2))); 427: 428: if (showVsb) 429: vsWidth = vsb.getPreferredSize().width; 430: } 431: 432: x3 = x4 - vsWidth; 433: y3 = y4 - hsHeight; 434: 435: // now set the layout 436: if (viewport != null) 437: viewport.setBounds(new Rectangle(x2 + vpi.left, y2 + vpi.top, 438: x3 - x2 - vpi.left - vpi.right, 439: y3 - y2 - vpi.top - vpi.bottom)); 440: 441: if (colHead != null) 442: colHead.setBounds(new Rectangle(x2, y1, x3 - x2, y2 - y1)); 443: 444: if (rowHead != null) 445: rowHead.setBounds(new Rectangle(x1, y2, x2 - x1, y3 - y2)); 446: 447: if (showVsb) 448: { 449: vsb.setVisible(true); 450: vsb.setBounds(new Rectangle(x3, y2, x4 - x3, y3 - y2 )); 451: } 452: else if (vsb != null) 453: vsb.setVisible(false); 454: 455: if (showHsb) 456: { 457: hsb.setVisible(true); 458: hsb.setBounds(new Rectangle(x2 , y3, x3 - x2, y4 - y3)); 459: } 460: else if (hsb != null) 461: hsb.setVisible(false); 462: 463: if (upperLeft != null) 464: upperLeft.setBounds(new Rectangle(x1, y1, x2 - x1, y2 - y1)); 465: 466: if (upperRight != null) 467: upperRight.setBounds(new Rectangle(x3, y1, x4 - x3, y2 - y1)); 468: 469: if (lowerLeft != null) 470: lowerLeft.setBounds(new Rectangle(x1, y3, x2 - x1, y4 - y3)); 471: 472: if (lowerRight != null) 473: lowerRight.setBounds(new Rectangle(x3, y3, x4 - x3, y4 - y3)); 474: } 475: 476: /** 477: * Returns the bounds of the border around a ScrollPane's viewport. 478: * 479: * @param scrollPane the ScrollPane for which's viewport the border 480: * is requested 481: * 482: * @deprecated As of Swing 1.1 replaced by 483: * {@link javax.swing.JScrollPane#getViewportBorderBounds}. 484: */ 485: public Rectangle getViewportBorderBounds(JScrollPane scrollPane) 486: { 487: return null; 488: } 489: 490: 491: }