Frames | No Frames |
1: /* BorderLayout.java -- A layout manager class 2: Copyright (C) 1999, 2002, 2005 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 java.awt; 40: 41: 42: /** 43: * This class implements a layout manager that positions components 44: * in certain sectors of the parent container. 45: * 46: * @author Aaron M. Renn (arenn@urbanophile.com) 47: * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) 48: */ 49: public class BorderLayout implements LayoutManager2, java.io.Serializable 50: { 51: 52: /** 53: * Constant indicating the top of the container 54: */ 55: public static final String NORTH = "North"; 56: 57: /** 58: * Constant indicating the bottom of the container 59: */ 60: public static final String SOUTH = "South"; 61: 62: /** 63: * Constant indicating the right side of the container 64: */ 65: public static final String EAST = "East"; 66: 67: /** 68: * Constant indicating the left side of the container 69: */ 70: public static final String WEST = "West"; 71: 72: /** 73: * Constant indicating the center of the container 74: */ 75: public static final String CENTER = "Center"; 76: 77: 78: /** 79: * The constant indicating the position before the first line of the 80: * layout. The exact position depends on the writing system: For a 81: * top-to-bottom orientation, it is the same as {@link #NORTH}, for 82: * a bottom-to-top orientation, it is the same as {@link #SOUTH}. 83: * 84: * <p>This constant is an older name for {@link #PAGE_START} which 85: * has exactly the same value. 86: * 87: * @since 1.2 88: */ 89: public static final String BEFORE_FIRST_LINE = "First"; 90: 91: /** 92: * The constant indicating the position after the last line of the 93: * layout. The exact position depends on the writing system: For a 94: * top-to-bottom orientation, it is the same as {@link #SOUTH}, for 95: * a bottom-to-top orientation, it is the same as {@link #NORTH}. 96: * 97: * <p>This constant is an older name for {@link #PAGE_END} which 98: * has exactly the same value. 99: * 100: * @since 1.2 101: */ 102: public static final String AFTER_LAST_LINE = "Last"; 103: 104: /** 105: * The constant indicating the position before the first item of the 106: * layout. The exact position depends on the writing system: For a 107: * left-to-right orientation, it is the same as {@link #WEST}, for 108: * a right-to-left orientation, it is the same as {@link #EAST}. 109: * 110: * <p>This constant is an older name for {@link #LINE_START} which 111: * has exactly the same value. 112: * 113: * @since 1.2 114: */ 115: public static final String BEFORE_LINE_BEGINS = "Before"; 116: 117: /** 118: * The constant indicating the position after the last item of the 119: * layout. The exact position depends on the writing system: For a 120: * left-to-right orientation, it is the same as {@link #EAST}, for 121: * a right-to-left orientation, it is the same as {@link #WEST}. 122: * 123: * <p>This constant is an older name for {@link #LINE_END} which 124: * has exactly the same value. 125: * 126: * @since 1.2 127: */ 128: public static final String AFTER_LINE_ENDS = "After"; 129: 130: /** 131: * The constant indicating the position before the first line of the 132: * layout. The exact position depends on the writing system: For a 133: * top-to-bottom orientation, it is the same as {@link #NORTH}, for 134: * a bottom-to-top orientation, it is the same as {@link #SOUTH}. 135: * 136: * @since 1.4 137: */ 138: public static final String PAGE_START = BEFORE_FIRST_LINE; 139: 140: /** 141: * The constant indicating the position after the last line of the 142: * layout. The exact position depends on the writing system: For a 143: * top-to-bottom orientation, it is the same as {@link #SOUTH}, for 144: * a bottom-to-top orientation, it is the same as {@link #NORTH}. 145: * 146: * @since 1.4 147: */ 148: public static final String PAGE_END = AFTER_LAST_LINE; 149: 150: /** 151: * The constant indicating the position before the first item of the 152: * layout. The exact position depends on the writing system: For a 153: * left-to-right orientation, it is the same as {@link #WEST}, for 154: * a right-to-left orientation, it is the same as {@link #EAST}. 155: * 156: * @since 1.4 157: */ 158: public static final String LINE_START = BEFORE_LINE_BEGINS; 159: 160: /** 161: * The constant indicating the position after the last item of the 162: * layout. The exact position depends on the writing system: For a 163: * left-to-right orientation, it is the same as {@link #EAST}, for 164: * a right-to-left orientation, it is the same as {@link #WEST}. 165: * 166: * @since 1.4 167: */ 168: public static final String LINE_END = AFTER_LINE_ENDS; 169: 170: 171: /** 172: * Serialization constant. 173: */ 174: private static final long serialVersionUID = -8658291919501921765L; 175: 176: 177: /** 178: * @serial 179: */ 180: private Component north; 181: 182: /** 183: * @serial 184: */ 185: private Component south; 186: 187: /** 188: * @serial 189: */ 190: private Component east; 191: 192: /** 193: * @serial 194: */ 195: private Component west; 196: 197: /** 198: * @serial 199: */ 200: private Component center; 201: 202: /** 203: * @serial 204: */ 205: private Component firstLine; 206: 207: /** 208: * @serial 209: */ 210: private Component lastLine; 211: 212: /** 213: * @serial 214: */ 215: private Component firstItem; 216: 217: /** 218: * @serial 219: */ 220: private Component lastItem; 221: 222: /** 223: * @serial The horizontal gap between components 224: */ 225: private int hgap; 226: 227: /** 228: * @serial The vertical gap between components 229: */ 230: private int vgap; 231: 232: 233: // Some constants for use with calcSize(). 234: private static final int MIN = 0; 235: private static final int MAX = 1; 236: private static final int PREF = 2; 237: 238: 239: /** 240: * Initializes a new instance of <code>BorderLayout</code> with no 241: * horiztonal or vertical gaps between components. 242: */ 243: public BorderLayout() 244: { 245: this(0,0); 246: } 247: 248: /** 249: * Initializes a new instance of <code>BorderLayout</code> with the 250: * specified horiztonal and vertical gaps between components. 251: * 252: * @param hgap The horizontal gap between components. 253: * @param vgap The vertical gap between components. 254: */ 255: public BorderLayout(int hgap, int vgap) 256: { 257: this.hgap = hgap; 258: this.vgap = vgap; 259: } 260: 261: /** 262: * Returns the horitzontal gap value. 263: * 264: * @return The horitzontal gap value. 265: */ 266: public int getHgap() 267: { 268: return(hgap); 269: } 270: 271: /** 272: * Sets the horizontal gap to the specified value. 273: * 274: * @param hgap The new horizontal gap. 275: */ 276: public void setHgap(int hgap) 277: { 278: this.hgap = hgap; 279: } 280: 281: /** 282: * Returns the vertical gap value. 283: * 284: * @return The vertical gap value. 285: */ 286: public int getVgap() 287: { 288: return(vgap); 289: } 290: 291: /** 292: * Sets the vertical gap to the specified value. 293: * 294: * @param vgap The new vertical gap value. 295: */ 296: public void setVgap(int vgap) 297: { 298: this.vgap = vgap; 299: } 300: 301: /** 302: * Adds a component to the layout in the specified constraint position, 303: * which must be one of the string constants defined in this class. 304: * 305: * @param component The component to add. 306: * @param constraints The constraint string. 307: * 308: * @exception IllegalArgumentException If the constraint object is not 309: * a string, or is not one of the specified constants in this class. 310: */ 311: public void addLayoutComponent(Component component, Object constraints) 312: { 313: if (constraints != null && ! (constraints instanceof String)) 314: throw new IllegalArgumentException("Constraint must be a string"); 315: 316: addLayoutComponent((String) constraints, component); 317: } 318: 319: /** 320: * Adds a component to the layout in the specified constraint position, 321: * which must be one of the string constants defined in this class. 322: * 323: * @param constraints The constraint string. 324: * @param component The component to add. 325: * 326: * @exception IllegalArgumentException If the constraint object is not 327: * one of the specified constants in this class. 328: * 329: * @deprecated This method is deprecated in favor of 330: * <code>addLayoutComponent(Component, Object)</code>. 331: */ 332: public void addLayoutComponent(String constraints, Component component) 333: { 334: String str = constraints; 335: 336: if (str == null || str.equals(CENTER)) 337: center = component; 338: else if (str.equals(NORTH)) 339: north = component; 340: else if (str.equals(SOUTH)) 341: south = component; 342: else if (str.equals(EAST)) 343: east = component; 344: else if (str.equals(WEST)) 345: west = component; 346: else if (str.equals(BEFORE_FIRST_LINE)) 347: firstLine = component; 348: else if (str.equals(AFTER_LAST_LINE)) 349: lastLine = component; 350: else if (str.equals(BEFORE_LINE_BEGINS)) 351: firstItem = component; 352: else if (str.equals(AFTER_LINE_ENDS)) 353: lastItem = component; 354: else 355: throw new IllegalArgumentException("Constraint value not valid: " + str); 356: } 357: 358: /** 359: * Removes the specified component from the layout. 360: * 361: * @param component The component to remove from the layout. 362: */ 363: public void removeLayoutComponent(Component component) 364: { 365: if (north == component) 366: north = null; 367: if (south == component) 368: south = null; 369: if (east == component) 370: east = null; 371: if (west == component) 372: west = null; 373: if (center == component) 374: center = null; 375: if (firstItem == component) 376: firstItem = null; 377: if (lastItem == component) 378: lastItem = null; 379: if (firstLine == component) 380: firstLine = null; 381: if (lastLine == component) 382: lastLine = null; 383: } 384: 385: /** 386: * Returns the minimum size of the specified container using this layout. 387: * 388: * @param target The container to calculate the minimum size for. 389: * 390: * @return The minimum size of the container 391: */ 392: public Dimension minimumLayoutSize(Container target) 393: { 394: return calcSize(target, MIN); 395: } 396: 397: /** 398: * Returns the preferred size of the specified container using this layout. 399: * 400: * @param target The container to calculate the preferred size for. 401: * 402: * @return The preferred size of the container 403: */ 404: public Dimension preferredLayoutSize(Container target) 405: { 406: return calcSize(target, PREF); 407: } 408: 409: /** 410: * Returns the maximum size of the specified container using this layout. 411: * 412: * @param target The container to calculate the maximum size for. 413: * 414: * @return The maximum size of the container 415: */ 416: public Dimension maximumLayoutSize(Container target) 417: { 418: return new Dimension (Integer.MAX_VALUE, Integer.MAX_VALUE); 419: } 420: 421: /** 422: * Returns the X axis alignment, which is a <code>float</code> indicating 423: * where along the X axis this container wishs to position its layout. 424: * 0 indicates align to the left, 1 indicates align to the right, and 0.5 425: * indicates align to the center. 426: * 427: * @param parent The parent container. 428: * 429: * @return The X alignment value. 430: */ 431: public float getLayoutAlignmentX(Container parent) 432: { 433: return 0.5F; 434: } 435: 436: /** 437: * Returns the Y axis alignment, which is a <code>float</code> indicating 438: * where along the Y axis this container wishs to position its layout. 439: * 0 indicates align to the top, 1 indicates align to the bottom, and 0.5 440: * indicates align to the center. 441: * 442: * @param parent The parent container. 443: * 444: * @return The Y alignment value. 445: */ 446: public float getLayoutAlignmentY(Container parent) 447: { 448: return 0.5F; 449: } 450: 451: /** 452: * Instructs this object to discard any layout information it might 453: * have cached. 454: * 455: * @param parent The parent container. 456: */ 457: public void invalidateLayout(Container parent) 458: { 459: // Nothing to do here. 460: } 461: 462: /** 463: * Lays out the specified container according to the constraints in this 464: * object. 465: * 466: * @param target The container to lay out. 467: */ 468: public void layoutContainer(Container target) 469: { 470: synchronized (target.getTreeLock()) 471: { 472: Insets i = target.getInsets(); 473: int top = i.top; 474: int bottom = target.height - i.bottom; 475: int left = i.left; 476: int right = target.width - i.right; 477: 478: boolean left_to_right = target.getComponentOrientation().isLeftToRight(); 479: 480: Component my_north = north; 481: Component my_east = east; 482: Component my_south = south; 483: Component my_west = west; 484: 485: // Note that we currently don't handle vertical layouts. 486: // Neither does JDK 1.3. 487: if (firstLine != null) 488: my_north = firstLine; 489: if (lastLine != null) 490: my_south = lastLine; 491: if (firstItem != null) 492: { 493: if (left_to_right) 494: my_west = firstItem; 495: else 496: my_east = firstItem; 497: } 498: if (lastItem != null) 499: { 500: if (left_to_right) 501: my_east = lastItem; 502: else 503: my_west = lastItem; 504: } 505: 506: if (my_north != null) 507: { 508: Dimension n = calcCompSize(my_north, PREF); 509: my_north.setBounds(left, top, right - left, n.height); 510: top += n.height + vgap; 511: } 512: 513: if (my_south != null) 514: { 515: Dimension s = calcCompSize(my_south, PREF); 516: my_south.setBounds(left, bottom - s.height, right - left, s.height); 517: bottom -= s.height + vgap; 518: } 519: 520: if (my_east != null) 521: { 522: Dimension e = calcCompSize(my_east, PREF); 523: my_east.setBounds(right - e.width, top, e.width, bottom - top); 524: right -= e.width + hgap; 525: } 526: 527: if (my_west != null) 528: { 529: Dimension w = calcCompSize(my_west, PREF); 530: my_west.setBounds(left, top, w.width, bottom - top); 531: left += w.width + hgap; 532: } 533: 534: if (center != null) 535: center.setBounds(left, top, right - left, bottom - top); 536: } 537: } 538: 539: /** 540: * Returns a string representation of this layout manager. 541: * 542: * @return A string representation of this object. 543: */ 544: public String toString() 545: { 546: return getClass().getName() + "[hgap=" + hgap + ",vgap=" + vgap + "]"; 547: } 548: 549: private Dimension calcCompSize(Component comp, int what) 550: { 551: if (comp == null || ! comp.isVisible()) 552: return new Dimension(0, 0); 553: if (what == MIN) 554: return comp.getMinimumSize(); 555: else if (what == MAX) 556: return comp.getMaximumSize(); 557: return comp.getPreferredSize(); 558: } 559: 560: /** 561: * This is a helper function used to compute the various sizes for this 562: * layout. 563: */ 564: private Dimension calcSize(Container target, int what) 565: { 566: synchronized (target.getTreeLock()) 567: { 568: Insets ins = target.getInsets(); 569: 570: ComponentOrientation orient = target.getComponentOrientation (); 571: boolean left_to_right = orient.isLeftToRight (); 572: 573: Component my_north = north; 574: Component my_east = east; 575: Component my_south = south; 576: Component my_west = west; 577: 578: // Note that we currently don't handle vertical layouts. Neither 579: // does JDK 1.3. 580: if (firstLine != null) 581: my_north = firstLine; 582: if (lastLine != null) 583: my_south = lastLine; 584: if (firstItem != null) 585: { 586: if (left_to_right) 587: my_west = firstItem; 588: else 589: my_east = firstItem; 590: } 591: if (lastItem != null) 592: { 593: if (left_to_right) 594: my_east = lastItem; 595: else 596: my_west = lastItem; 597: } 598: 599: Dimension ndim = calcCompSize(my_north, what); 600: Dimension sdim = calcCompSize(my_south, what); 601: Dimension edim = calcCompSize(my_east, what); 602: Dimension wdim = calcCompSize(my_west, what); 603: Dimension cdim = calcCompSize(center, what); 604: 605: int width = edim.width + cdim.width + wdim.width + (hgap * 2); 606: // Check for overflow. 607: if (width < edim.width || width < cdim.width || width < cdim.width) 608: width = Integer.MAX_VALUE; 609: 610: if (ndim.width > width) 611: width = ndim.width; 612: if (sdim.width > width) 613: width = sdim.width; 614: 615: width += (ins.left + ins.right); 616: 617: int height = edim.height; 618: if (cdim.height > height) 619: height = cdim.height; 620: if (wdim.height > height) 621: height = wdim.height; 622: 623: int addedHeight = height + (ndim.height + sdim.height + (vgap * 2) 624: + ins.top + ins.bottom); 625: // Check for overflow. 626: if (addedHeight < height) 627: height = Integer.MAX_VALUE; 628: else 629: height = addedHeight; 630: 631: return(new Dimension(width, height)); 632: } 633: } 634: 635: /** 636: * Return the component at the indicated location, or null if no component 637: * is at that location. The constraints argument must be one of the 638: * location constants specified by this class. 639: * @param constraints the location 640: * @return the component at that location, or null 641: * @throws IllegalArgumentException if the constraints argument is not 642: * recognized 643: * @since 1.5 644: */ 645: public Component getLayoutComponent(Object constraints) 646: { 647: if (constraints == CENTER) 648: return center; 649: if (constraints == NORTH) 650: return north; 651: if (constraints == EAST) 652: return east; 653: if (constraints == SOUTH) 654: return south; 655: if (constraints == WEST) 656: return west; 657: if (constraints == PAGE_START) 658: return firstLine; 659: if (constraints == PAGE_END) 660: return lastLine; 661: if (constraints == LINE_START) 662: return firstItem; 663: if (constraints == LINE_END) 664: return lastItem; 665: throw new IllegalArgumentException("constraint " + constraints 666: + " is not recognized"); 667: } 668: 669: /** 670: * Return the component at the specified location, which must be one 671: * of the absolute constants such as CENTER or SOUTH. The container's 672: * orientation is used to map this location to the correct corresponding 673: * component, so for instance in a right-to-left container, a request 674: * for the EAST component could return the LINE_END component. This will 675: * return null if no component is available at the given location. 676: * @param container the container whose orientation is used 677: * @param constraints the absolute location of the component 678: * @return the component at the location, or null 679: * @throws IllegalArgumentException if the constraint is not recognized 680: */ 681: public Component getLayoutComponent(Container container, Object constraints) 682: { 683: ComponentOrientation orient = container.getComponentOrientation(); 684: if (constraints == CENTER) 685: return center; 686: // Note that we don't support vertical layouts. 687: if (constraints == NORTH) 688: return north; 689: if (constraints == SOUTH) 690: return south; 691: if (constraints == WEST) 692: { 693: // Note that relative layout takes precedence. 694: if (orient.isLeftToRight()) 695: return firstItem == null ? west : firstItem; 696: return lastItem == null ? west : lastItem; 697: } 698: if (constraints == EAST) 699: { 700: // Note that relative layout takes precedence. 701: if (orient.isLeftToRight()) 702: return lastItem == null ? east : lastItem; 703: return firstItem == null ? east : firstItem; 704: } 705: throw new IllegalArgumentException("constraint " + constraints 706: + " is not recognized"); 707: } 708: 709: /** 710: * Return the constraint corresponding to a component in this layout. 711: * If the component is null, or is not in this layout, returns null. 712: * Otherwise, this will return one of the constraint constants defined 713: * in this class. 714: * @param c the component 715: * @return the constraint, or null 716: * @since 1.5 717: */ 718: public Object getConstraints(Component c) 719: { 720: if (c == null) 721: return null; 722: if (c == center) 723: return CENTER; 724: if (c == north) 725: return NORTH; 726: if (c == east) 727: return EAST; 728: if (c == south) 729: return SOUTH; 730: if (c == west) 731: return WEST; 732: if (c == firstLine) 733: return PAGE_START; 734: if (c == lastLine) 735: return PAGE_END; 736: if (c == firstItem) 737: return LINE_START; 738: if (c == lastItem) 739: return LINE_END; 740: return null; 741: } 742: }