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: /**
  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: }