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