Source for java.awt.BorderLayout

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