GNU Classpath (0.20) | |
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 464: * in this 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: 474: ComponentOrientation orient = target.getComponentOrientation (); 475: boolean left_to_right = orient.isLeftToRight (); 476: 477: Component my_north = north; 478: Component my_east = east; 479: Component my_south = south; 480: Component my_west = west; 481: 482: // Note that we currently don't handle vertical layouts. Neither 483: // does JDK 1.3. 484: if (firstLine != null) 485: my_north = firstLine; 486: if (lastLine != null) 487: my_south = lastLine; 488: if (firstItem != null) 489: { 490: if (left_to_right) 491: my_west = firstItem; 492: else 493: my_east = firstItem; 494: } 495: if (lastItem != null) 496: { 497: if (left_to_right) 498: my_east = lastItem; 499: else 500: my_west = lastItem; 501: } 502: 503: Dimension c = calcCompSize(center, PREF); 504: Dimension n = calcCompSize(my_north, PREF); 505: Dimension s = calcCompSize(my_south, PREF); 506: Dimension e = calcCompSize(my_east, PREF); 507: Dimension w = calcCompSize(my_west, PREF); 508: int targetWidth = target.getWidth(); 509: int targetHeight = target.getHeight(); 510: 511: /* 512: <-> hgap <-> hgap 513: +----------------------------+ } 514: |t | } i.top 515: | +----------------------+ | --- y1 } 516: | |n | | 517: | +----------------------+ | } vgap 518: | +---+ +----------+ +---+ | --- y2 } } 519: | |w | |c | |e | | } hh 520: | +---+ +----------+ +---+ | } vgap } 521: | +----------------------+ | --- y3 } 522: | |s | | 523: | +----------------------+ | } 524: | | } i.bottom 525: +----------------------------+ } 526: |x1 |x2 |x3 527: <----------------------> 528: <--> ww <--> 529: i.left i.right 530: */ 531: 532: int x1 = i.left; 533: int x2 = x1 + w.width + (w.width == 0 ? 0 : hgap); 534: int x3; 535: if (targetWidth <= i.right + e.width) 536: x3 = x2 + w.width + (w.width == 0 ? 0 : hgap); 537: else 538: x3 = targetWidth - i.right - e.width; 539: int ww = targetWidth - i.right - i.left; 540: 541: int y1 = i.top; 542: int y2 = y1 + n.height + (n.height == 0 ? 0 : vgap); 543: int midh = Math.max(e.height, Math.max(w.height, c.height)); 544: int y3; 545: if (targetHeight <= i.bottom + s.height) 546: y3 = y2 + midh + vgap; 547: else 548: y3 = targetHeight - i.bottom - s.height; 549: int hh = y3-y2-(s.height == 0 ? 0 : vgap); 550: 551: setBounds(center, x2, y2, x3-x2-(w.width == 0 ? 0 : hgap), hh); 552: setBounds(my_north, x1, y1, ww, n.height); 553: setBounds(my_south, x1, y3, ww, s.height); 554: setBounds(my_west, x1, y2, w.width, hh); 555: setBounds(my_east, x3, y2, e.width, hh); 556: } 557: } 558: 559: /** 560: * Returns a string representation of this layout manager. 561: * 562: * @return A string representation of this object. 563: */ 564: public String toString() 565: { 566: return getClass().getName() + "[hgap=" + hgap + ",vgap=" + vgap + "]"; 567: } 568: 569: /** 570: * This is a convenience method to set the bounds on a component. 571: * If the indicated component is null, nothing is done. 572: */ 573: private void setBounds(Component comp, int x, int y, int w, int h) 574: { 575: if (comp == null) 576: return; 577: comp.setBounds(x, y, w, h); 578: } 579: 580: private Dimension calcCompSize(Component comp, int what) 581: { 582: if (comp == null || !comp.isVisible()) 583: return new Dimension(0, 0); 584: if (what == MIN) 585: return comp.getMinimumSize(); 586: else if (what == MAX) 587: return comp.getMaximumSize(); 588: return comp.getPreferredSize(); 589: } 590: 591: /** 592: * This is a helper function used to compute the various sizes for 593: * this layout. 594: */ 595: private Dimension calcSize(Container target, int what) 596: { 597: synchronized (target.getTreeLock ()) 598: { 599: Insets ins = target.getInsets(); 600: 601: ComponentOrientation orient = target.getComponentOrientation (); 602: boolean left_to_right = orient.isLeftToRight (); 603: 604: Component my_north = north; 605: Component my_east = east; 606: Component my_south = south; 607: Component my_west = west; 608: 609: // Note that we currently don't handle vertical layouts. Neither 610: // does JDK 1.3. 611: if (firstLine != null) 612: my_north = firstLine; 613: if (lastLine != null) 614: my_south = lastLine; 615: if (firstItem != null) 616: { 617: if (left_to_right) 618: my_west = firstItem; 619: else 620: my_east = firstItem; 621: } 622: if (lastItem != null) 623: { 624: if (left_to_right) 625: my_east = lastItem; 626: else 627: my_west = lastItem; 628: } 629: 630: Dimension ndim = calcCompSize(my_north, what); 631: Dimension sdim = calcCompSize(my_south, what); 632: Dimension edim = calcCompSize(my_east, what); 633: Dimension wdim = calcCompSize(my_west, what); 634: Dimension cdim = calcCompSize(center, what); 635: 636: int width = edim.width + cdim.width + wdim.width + (hgap * 2); 637: // Check for overflow. 638: if (width < edim.width || width < cdim.width || width < cdim.width) 639: width = Integer.MAX_VALUE; 640: 641: if (ndim.width > width) 642: width = ndim.width; 643: if (sdim.width > width) 644: width = sdim.width; 645: 646: width += (ins.left + ins.right); 647: 648: int height = edim.height; 649: if (cdim.height > height) 650: height = cdim.height; 651: if (wdim.height > height) 652: height = wdim.height; 653: 654: int addedHeight = height + (ndim.height + sdim.height + (vgap * 2) 655: + ins.top + ins.bottom); 656: // Check for overflow. 657: if (addedHeight < height) 658: height = Integer.MAX_VALUE; 659: else 660: height = addedHeight; 661: 662: return(new Dimension(width, height)); 663: } 664: } 665: 666: /** 667: * Return the component at the indicated location, or null if no component 668: * is at that location. The constraints argument must be one of the 669: * location constants specified by this class. 670: * @param constraints the location 671: * @return the component at that location, or null 672: * @throws IllegalArgumentException if the constraints argument is not 673: * recognized 674: * @since 1.5 675: */ 676: public Component getLayoutComponent(Object constraints) 677: { 678: if (constraints == CENTER) 679: return center; 680: if (constraints == NORTH) 681: return north; 682: if (constraints == EAST) 683: return east; 684: if (constraints == SOUTH) 685: return south; 686: if (constraints == WEST) 687: return west; 688: if (constraints == PAGE_START) 689: return firstLine; 690: if (constraints == PAGE_END) 691: return lastLine; 692: if (constraints == LINE_START) 693: return firstItem; 694: if (constraints == LINE_END) 695: return lastItem; 696: throw new IllegalArgumentException("constraint " + constraints 697: + " is not recognized"); 698: } 699: 700: /** 701: * Return the component at the specified location, which must be one 702: * of the absolute constants such as CENTER or SOUTH. The container's 703: * orientation is used to map this location to the correct corresponding 704: * component, so for instance in a right-to-left container, a request 705: * for the EAST component could return the LINE_END component. This will 706: * return null if no component is available at the given location. 707: * @param container the container whose orientation is used 708: * @param constraints the absolute location of the component 709: * @return the component at the location, or null 710: * @throws IllegalArgumentException if the constraint is not recognized 711: */ 712: public Component getLayoutComponent(Container container, Object constraints) 713: { 714: ComponentOrientation orient = container.getComponentOrientation(); 715: if (constraints == CENTER) 716: return center; 717: // Note that we don't support vertical layouts. 718: if (constraints == NORTH) 719: return north; 720: if (constraints == SOUTH) 721: return south; 722: if (constraints == WEST) 723: { 724: // Note that relative layout takes precedence. 725: if (orient.isLeftToRight()) 726: return firstItem == null ? west : firstItem; 727: return lastItem == null ? west : lastItem; 728: } 729: if (constraints == EAST) 730: { 731: // Note that relative layout takes precedence. 732: if (orient.isLeftToRight()) 733: return lastItem == null ? east : lastItem; 734: return firstItem == null ? east : firstItem; 735: } 736: throw new IllegalArgumentException("constraint " + constraints 737: + " is not recognized"); 738: } 739: 740: /** 741: * Return the constraint corresponding to a component in this layout. 742: * If the component is null, or is not in this layout, returns null. 743: * Otherwise, this will return one of the constraint constants defined 744: * in this class. 745: * @param c the component 746: * @return the constraint, or null 747: * @since 1.5 748: */ 749: public Object getConstraints(Component c) 750: { 751: if (c == null) 752: return null; 753: if (c == center) 754: return CENTER; 755: if (c == north) 756: return NORTH; 757: if (c == east) 758: return EAST; 759: if (c == south) 760: return SOUTH; 761: if (c == west) 762: return WEST; 763: if (c == firstLine) 764: return PAGE_START; 765: if (c == lastLine) 766: return PAGE_END; 767: if (c == firstItem) 768: return LINE_START; 769: if (c == lastItem) 770: return LINE_END; 771: return null; 772: } 773: }
GNU Classpath (0.20) |