Source for javax.swing.SpringLayout

   1: /* SpringLayout.java -- 
   2:    Copyright (C) 2004, 2006, 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 javax.swing;
  40: 
  41: import java.awt.Component;
  42: import java.awt.Container;
  43: import java.awt.Dimension;
  44: import java.awt.LayoutManager2;
  45: import java.util.HashMap;
  46: import java.util.Map;
  47: 
  48: /**
  49:  * A very flexible layout manager. Components are laid out by defining the
  50:  * relationships between them. The relationships are expressed as
  51:  * {@link Spring}s. You can attach a Spring for each edge of a component and
  52:  * link it to an edge of a different component. For example, you can say,
  53:  * the northern edge of component A should be attached to the southern edge
  54:  * of component B, and the space between them should be something between
  55:  * x and y pixels, and preferably z pixels.
  56:  * <p>While quite simple, this layout manager can be used to emulate most other
  57:  * layout managers, and can also be used to solve some layout problems, which
  58:  * would be hard to solve with other layout managers.</p>
  59:  *
  60:  * @author Roman Kennke (roman@ontographics.com)
  61:  */
  62: public class SpringLayout implements LayoutManager2
  63: {
  64: 
  65:   /** The right edge of a component. */
  66:   public static final String EAST = "East";
  67: 
  68:   /** The top edge of a component. */
  69:   public static final String NORTH = "North";
  70: 
  71:   /** The bottom edge of a component. */
  72:   public static final String SOUTH = "South";
  73: 
  74:   /** The left edge of a component. */
  75:   public static final String WEST = "West";
  76: 
  77:   /** maps components to their constraints. */
  78:   private Map constraintsMap;
  79: 
  80:   /**
  81:    * The constraints that define the relationships between components.
  82:    * Each Constraints object can hold 4 Springs: one for each edge of the
  83:    * component. Additionally it can hold Springs for the components width
  84:    * and the components height. Since the height and width constraints are
  85:    * dependend on the other constraints, a component can be over-constraint.
  86:    * In this case (like when all of NORTH, SOUTH and HEIGHT are constraint),
  87:    * the values are adjusted, so that the mathematics still hold true.
  88:    *
  89:    * @author Roman Kennke (roman@ontographics.com)
  90:    */
  91:   public static class Constraints
  92:   {
  93: 
  94:     // The constraints for each edge, and width and height.
  95:     /** The Spring for the left edge. */
  96:     private Spring x;
  97: 
  98:     /** The Spring for the upper edge. */
  99:     private Spring y;
 100: 
 101:     /** The Spring for the height. */
 102:     private Spring height;
 103: 
 104:     /** The Spring for the width. */
 105:     private Spring width;
 106: 
 107:     /** The Spring for the right edge. */
 108:     private Spring east;
 109: 
 110:     /** The Spring for the bottom edge. */
 111:     private Spring south;
 112: 
 113:     /** 
 114:      In each axis the user can set three values, i.e. x, width, east, if all
 115:      three are set, then there's no room for manoeuvre so in those cases the 
 116:      third will be described by the below spring which is calculated in terms 
 117:      of the other two
 118:     */
 119:     private Spring v;
 120:     private Spring h;
 121: 
 122:     /**
 123:      * Creates a new Constraints object.
 124:      * There is no constraint set.
 125:      */
 126:     public Constraints()
 127:     {
 128:       x = y = height = width = east = south = v = h = null;
 129:     }
 130: 
 131:     /**
 132:      * Creates a new Constraints object.
 133:      *
 134:      * @param x the constraint for the left edge of the component.
 135:      * @param y the constraint for the upper edge of the component.
 136:      */
 137:     public Constraints(Spring x, Spring y)
 138:     {
 139:       this.x = x;
 140:       this.y = y;
 141:       width = height = east = south = v = h = null;
 142:     }
 143: 
 144:     /**
 145:      * Creates a new Constraints object.
 146:      *
 147:      * @param x the constraint for the left edge of the component.
 148:      * @param y the constraint for the upper edge of the component.
 149:      * @param width the constraint for the width of the component.
 150:      * @param height the constraint for the height of the component.
 151:      */
 152:     public Constraints(Spring x, Spring y, Spring width, Spring height)
 153:     {
 154:       this.x = x;
 155:       this.y = y;
 156:       this.width = width;
 157:       this.height = height;
 158:       east = south = v = h = null;
 159:     }
 160: 
 161:     /**
 162:      * Create a new Constraints object which tracks the indicated
 163:      * component.  The x and y positions for this Constraints object
 164:      * are constant Springs created with the component's location at
 165:      * the time this constructor is called.  The width and height
 166:      * of this Constraints are Springs created using
 167:      * {@link Spring#width(Component)} and {@link Spring#height(Component)},
 168:      * respectively.
 169:      * @param component the component to track
 170:      * @since 1.5
 171:      */
 172:     public Constraints(Component component)
 173:     {
 174:       this(Spring.constant(component.getX()),
 175:            Spring.constant(component.getY()),
 176:            Spring.width(component),
 177:            Spring.height(component));
 178:     }
 179: 
 180:     /**
 181:      * Returns the constraint for the edge with the <code>edgeName</code>.
 182:      * This is expected to be one of
 183:      * {@link #EAST}, {@link #WEST}, {@link #NORTH} or {@link #SOUTH}.
 184:      *
 185:      * @param edgeName the name of the edge.
 186:      * @return the constraint for the specified edge.
 187:      */
 188:     public Spring getConstraint(String edgeName)
 189:     {
 190:       Spring retVal = null;
 191:       if (edgeName.equals(SpringLayout.NORTH))
 192:     retVal = getY();
 193:       else if (edgeName.equals(SpringLayout.WEST))
 194:         retVal = getX();
 195:       else if (edgeName.equals(SpringLayout.SOUTH))
 196:         retVal = getSouth();
 197:       else if (edgeName.equals(SpringLayout.EAST))
 198:         retVal = getEast();
 199:       return retVal;
 200:     }
 201: 
 202:     /**
 203:      * Returns the constraint for the height of the component.
 204:      *
 205:      * @return the height constraint. 
 206:      */
 207:     public Spring getHeight()
 208:     {
 209:       if (height != null)
 210:         return height;
 211:       else if ((v == null) && (y != null) && (south != null))
 212:           v = Spring.sum(south, Spring.minus(y));
 213:       return v;
 214:     }
 215: 
 216:     /**
 217:      * Returns the constraint for the width of the component.
 218:      *
 219:      * @return the width constraint.
 220:      */
 221:     public Spring getWidth()
 222:     {
 223:       if (width != null)
 224:         return width;
 225:       else if ((h == null) && (x != null) && (east != null))
 226:         h = Spring.sum(east, Spring.minus(x));
 227:       return h;
 228:     }
 229: 
 230:     /**
 231:      * Returns the constraint for the left edge of the component.
 232:      *
 233:      * @return the left-edge constraint (== WEST).
 234:      */
 235:     public Spring getX()
 236:     {
 237:       if (x != null)
 238:         return x;
 239:       else if ((h == null) && (width != null) && (east != null))
 240:         h = Spring.sum(east, Spring.minus(width));
 241:       return h;
 242:     }
 243: 
 244:     /**
 245:      * Returns the constraint for the upper edge of the component.
 246:      *
 247:      * @return the upper-edge constraint (== NORTH).
 248:      */
 249:     public Spring getY()
 250:     {
 251:       if (y != null)
 252:         return y;
 253:       else if ((v == null) && (height != null) && (south != null))
 254:         v = Spring.sum(south, Spring.minus(height));
 255:       return v;
 256:     }
 257: 
 258:     /**
 259:      * Returns the constraint for the lower edge of the component.
 260:      *
 261:      * @return the lower-edge constraint (== SOUTH).
 262:      */
 263:     public Spring getSouth()
 264:     {
 265:       if (south != null)
 266:         return south;
 267:       else if ((v == null) && (height != null) && (y != null))
 268:         v = Spring.sum(y, height);
 269:       return v;
 270:     }
 271: 
 272:     /**
 273:      * Returns the constraint for the right edge of the component.
 274:      *
 275:      * @return the right-edge constraint (== EAST).
 276:      */
 277:     public Spring getEast()
 278:     {
 279:       if (east != null)
 280:         return east;
 281:       else if ((h == null) && (width != null) && (x != null))
 282:         h = Spring.sum(x, width);
 283:       return h;
 284:     }
 285: 
 286:     /**
 287:      * Sets a constraint for the specified edge. If this leads to an
 288:      * over-constrained situation, the constraints get adjusted, so that
 289:      * the mathematics still hold true.
 290:      *
 291:      * @param edgeName the name of the edge, one of {@link #EAST},
 292:      *     {@link #WEST}, {@link #NORTH} or {@link #SOUTH}.
 293:      * @param s the constraint to be set.
 294:      */
 295:     public void setConstraint(String edgeName, Spring s)
 296:     {
 297:     
 298:       if (edgeName.equals(SpringLayout.WEST))
 299:         setX(s);
 300:       else if (edgeName.equals(SpringLayout.NORTH))
 301:         setY(s);
 302:       else if (edgeName.equals(SpringLayout.EAST))
 303:         setEast(s);
 304:       else if (edgeName.equals(SpringLayout.SOUTH))
 305:         setSouth(s);
 306: 
 307:     }
 308: 
 309:     /**
 310:      * Sets the height-constraint.
 311:      *
 312:      * @param s the constraint to be set.
 313:      */
 314:     public void setHeight(Spring s)
 315:     {
 316:       height = s;
 317:       v = null;
 318:       if ((south != null) && (y != null) && (height != null))
 319:           south = null;
 320:     }
 321: 
 322:     /**
 323:      * Sets the width-constraint.
 324:      *
 325:      * @param s the constraint to be set.
 326:      */
 327:     public void setWidth(Spring s)
 328:     {
 329:       width = s;
 330:       h = null;
 331:       if ((east != null) && (x != null) && (width != null))
 332:         east = null;
 333:     }
 334: 
 335:     /**
 336:      * Sets the WEST-constraint.
 337:      *
 338:      * @param s the constraint to be set.
 339:      */
 340:     public void setX(Spring s)
 341:     {
 342:       x = s;
 343:       h = null;
 344:       if ((width != null) && (east != null) && (x != null))
 345:         width = null;
 346:     }
 347: 
 348:     /**
 349:      * Sets the NORTH-constraint.
 350:      *
 351:      * @param s the constraint to be set.
 352:      */
 353:     public void setY(Spring s)
 354:     {
 355:       y = s;
 356:       v = null;
 357:       if ((height != null) && (south != null) && (y != null))
 358:         height = null;
 359:     }
 360: 
 361:     /**
 362:      * Sets the SOUTH-constraint.
 363:      *
 364:      * @param s the constraint to be set.
 365:      */
 366:     public void setSouth(Spring s)
 367:     {
 368:       south = s;
 369:       v = null;
 370:       if ((height != null) && (south != null) && (y != null))
 371:         y = null;
 372:     }
 373: 
 374:     /**
 375:      * Sets the EAST-constraint.
 376:      *
 377:      * @param s the constraint to be set.
 378:      */
 379:     public void setEast(Spring s)
 380:     {
 381:       east = s;
 382:       h = null;
 383:       if ((width != null) && (east != null) && (x != null))
 384:         x = null;
 385:     }
 386: 
 387:     public void dropCalcResult()
 388:     {
 389:       if (x != null)
 390:         x.setValue(Spring.UNSET);
 391:       if (y != null)
 392:         y.setValue(Spring.UNSET);
 393:       if (width != null)
 394:         width.setValue(Spring.UNSET);
 395:       if (height != null)
 396:         height.setValue(Spring.UNSET);
 397:       if (east != null) 
 398:         east.setValue(Spring.UNSET);
 399:       if (south != null)
 400:         south.setValue(Spring.UNSET);
 401:       if (h != null)
 402:         h.setValue(Spring.UNSET);
 403:       if (v != null)
 404:         v.setValue(Spring.UNSET);
 405:     }
 406:   }
 407: 
 408:   /**
 409:    * Creates a new SpringLayout.
 410:    */
 411:   public SpringLayout()
 412:   {
 413:     constraintsMap = new HashMap();
 414:   }
 415: 
 416:   /**
 417:    * Adds a layout component and a constraint object to this layout.
 418:    * This method is usually only called by a {@link java.awt.Container}s add
 419:    * method.
 420:    *
 421:    * @param component the component to be added.
 422:    * @param constraint the constraint to be set.
 423:    */
 424:   public void addLayoutComponent(Component component, Object constraint)
 425:   {
 426:     constraintsMap.put(component, constraint);
 427:   }
 428: 
 429:   /**
 430:    * Adds a layout component and a constraint object to this layout.
 431:    * This method is usually only called by a {@link java.awt.Container}s add
 432:    * method. This method does nothing, since SpringLayout does not manage
 433:    * String-indexed components.
 434:    *
 435:    * @param name  the name.
 436:    * @param c the component to be added.
 437:    */
 438:   public void addLayoutComponent(String name, Component c)
 439:   {
 440:     // do nothing here.
 441:   }
 442: 
 443:   /**
 444:    * The trick to SpringLayout is that the network of Springs needs to
 445:    * completely created before the positioning results are generated.
 446:    *
 447:    * Using the springs directly during network creation will set their values 
 448:    * before the network is completed, Using Deferred Springs during creation of 
 449:    * the network allows all the edges to be connected together and the network 
 450:    * to be created without resolving the Springs until their results need to be 
 451:    * known, at which point the network is complete and the spring addition and 
 452:    * and substitution calculations will work on a complete and valid network.
 453:    *
 454:    * @author Caolan McNamara (caolanm@redhat.com)
 455:    */
 456:   private static class DeferredSpring extends Spring 
 457:   {
 458:     private SpringLayout sl;
 459:     private String edgeName;
 460:     private Component c;
 461: 
 462:     public String toString()
 463:     {
 464:       return "DeferredSpring of edge" + edgeName + " of " + "something";
 465:     }
 466: 
 467:     public DeferredSpring(SpringLayout s, String edge, Component component)
 468:     {
 469:         sl = s;
 470:         edgeName = edge;
 471:         c = component;
 472:     }
 473: 
 474:     private Spring resolveSpring() 
 475:     {
 476:         return sl.getConstraints(c).getConstraint(edgeName);
 477:     }
 478: 
 479:     public int getMaximumValue() 
 480:     {
 481:         return resolveSpring().getMaximumValue();
 482:     }
 483: 
 484:     public int getMinimumValue() 
 485:     {
 486:         return resolveSpring().getMinimumValue();
 487:     }
 488: 
 489:     public int getPreferredValue() 
 490:     {
 491:         return resolveSpring().getPreferredValue();
 492:     }
 493: 
 494:     public int getValue() 
 495:     {
 496:         int nRet = resolveSpring().getValue();
 497:         if (nRet == Spring.UNSET)
 498:             nRet = getPreferredValue();
 499:         return nRet;
 500:     }
 501: 
 502:     public void setValue(int size) 
 503:     {
 504:         resolveSpring().setValue(size);
 505:     }
 506:   }
 507: 
 508:   private abstract static class DeferredDimension extends Spring
 509:   {
 510:     private int value;
 511: 
 512:     public DeferredDimension()
 513:     {
 514:       value = Spring.UNSET;
 515:     }
 516: 
 517:     public void setValue(int val)
 518:     {
 519:       value = val;
 520:     }
 521: 
 522:     public int getValue()
 523:     {
 524:       if (value == Spring.UNSET)
 525:           return getPreferredValue();
 526:       return value;
 527:     }
 528:   }
 529: 
 530:   private static class DeferredWidth extends DeferredDimension
 531:   {
 532:     private Component c;
 533: 
 534: 
 535:     public DeferredWidth(Component component)
 536:     {
 537:         c = component;
 538:     }
 539: 
 540:     public String toString()
 541:     {
 542:       return "DeferredWidth of " + "something";
 543:     }
 544: 
 545:     //clip max to a value we can do meaningful calculation with
 546:     public int getMaximumValue() 
 547:     {
 548:         int widget_width = c.getMaximumSize().width;
 549:         return Math.min(Short.MAX_VALUE, widget_width);
 550:     }
 551: 
 552:     public int getMinimumValue() 
 553:     {
 554:         return c.getMinimumSize().width;
 555:     }
 556: 
 557:     public int getPreferredValue() 
 558:     {
 559:         return c.getPreferredSize().width;
 560:     }
 561:   }
 562: 
 563:   private static class DeferredHeight extends DeferredDimension
 564:   {
 565:     private Component c;
 566: 
 567:     public String toString()
 568:     {
 569:         return "DeferredHeight of " + "something";
 570:     }
 571: 
 572:     public DeferredHeight(Component component)
 573:     {
 574:         c = component;
 575:     }
 576: 
 577:     //clip max to a value we can do meaningful calculations with it
 578:     public int getMaximumValue() 
 579:     {
 580:         int widget_height = c.getMaximumSize().height;
 581:         return Math.min(Short.MAX_VALUE, widget_height);
 582:     }
 583: 
 584:     public int getMinimumValue() 
 585:     {
 586:         return c.getMinimumSize().height;
 587:     }
 588: 
 589:     public int getPreferredValue() 
 590:     {
 591:         return c.getPreferredSize().height;
 592:     }
 593:   }
 594: 
 595:   /**
 596:    * Returns the constraint of the edge named by <code>edgeName</code>.
 597:    *
 598:    * @param c the component from which to get the constraint.
 599:    * @param edgeName the name of the edge, one of {@link #EAST},
 600:    *     {@link #WEST}, {@link #NORTH} or {@link #SOUTH}.
 601:    * @return the constraint of the edge <code>edgeName</code> of the
 602:    * component c.
 603:    */
 604:   public Spring getConstraint(String edgeName, Component c)
 605:   {
 606:     return new DeferredSpring(this, edgeName, c);
 607:   }
 608: 
 609:   /**
 610:    * Returns the {@link Constraints} object associated with the specified
 611:    * component.
 612:    *
 613:    * @param c the component for which to determine the constraint.
 614:    * @return the {@link Constraints} object associated with the specified
 615:    *      component.
 616:    */
 617:   public SpringLayout.Constraints getConstraints(Component c)
 618:   {
 619:     Constraints constraints = (Constraints) constraintsMap.get(c);
 620: 
 621:     if (constraints == null)
 622:     {
 623:       constraints = new Constraints();
 624: 
 625:       constraints.setWidth(new DeferredWidth(c));
 626:       constraints.setHeight(new DeferredHeight(c));
 627:       constraints.setX(Spring.constant(0));
 628:       constraints.setY(Spring.constant(0));
 629: 
 630:       constraintsMap.put(c, constraints);
 631:     }
 632: 
 633:     return constraints;
 634:   }
 635: 
 636:   /**
 637:    * Returns the X alignment of the Container <code>p</code>.
 638:    * 
 639:    * @param p
 640:    *          the {@link java.awt.Container} for which to determine the X
 641:    *          alignment.
 642:    * @return always 0.0
 643:    */
 644:   public float getLayoutAlignmentX(Container p)
 645:   {
 646:     return 0.0F;
 647:   }
 648: 
 649:   /**
 650:    * Returns the Y alignment of the Container <code>p</code>.
 651:    *
 652:    * @param p the {@link java.awt.Container} for which to determine the Y
 653:    *     alignment.
 654:    * @return always 0.0
 655:    */
 656:   public float getLayoutAlignmentY(Container p)
 657:   {
 658:     return 0.0F;
 659:   }
 660: 
 661:   /**
 662:    * Recalculate a possibly cached layout.
 663:    */
 664:   public void invalidateLayout(Container p)
 665:   {
 666:     // nothing to do here yet
 667:   }
 668: 
 669:   private Constraints initContainer(Container p)
 670:   {
 671:     Constraints c = getConstraints(p);
 672: 
 673:     c.setX(Spring.constant(0));
 674:     c.setY(Spring.constant(0));
 675:     c.setWidth(null);
 676:     c.setHeight(null);
 677:     if (c.getEast() == null)
 678:       c.setEast(Spring.constant(0, 0, Integer.MAX_VALUE));
 679:     if (c.getSouth() == null) 
 680:       c.setSouth(Spring.constant(0, 0, Integer.MAX_VALUE));
 681: 
 682:     return c;
 683:   }
 684: 
 685:   /**
 686:    * Lays out the container <code>p</code>.
 687:    *
 688:    * @param p the container to be laid out.
 689:    */
 690:   public void layoutContainer(Container p)
 691:   {
 692:     java.awt.Insets insets = p.getInsets();
 693: 
 694:     Component[] components = p.getComponents();
 695: 
 696:     Constraints cs = initContainer(p);
 697:     cs.dropCalcResult();
 698: 
 699:     for (int index = 0 ; index < components.length; index++)
 700:     {
 701:         Component c = components[index];
 702:         getConstraints(c).dropCalcResult();
 703:     }
 704: 
 705:     int offsetX = p.getInsets().left;
 706:     int offsetY = p.getInsets().right;
 707: 
 708:     cs.getX().setValue(0);
 709:     cs.getY().setValue(0);
 710:     cs.getWidth().setValue(p.getWidth() - offsetX - insets.right);
 711:     cs.getHeight().setValue(p.getHeight() - offsetY - insets.bottom);
 712: 
 713:     for (int index = 0; index < components.length; index++)
 714:     {
 715:       Component c = components[index];
 716: 
 717:       Constraints constraints = getConstraints(c);
 718:       
 719:       int x = constraints.getX().getValue();
 720:       int y = constraints.getY().getValue();
 721:       int width = constraints.getWidth().getValue();
 722:       int height = constraints.getHeight().getValue();
 723:       
 724:       c.setBounds(x + offsetX, y + offsetY, width, height);
 725:     }
 726:   }
 727: 
 728:   /**
 729:    * Calculates the maximum size of the layed out container. This
 730:    * respects the maximum sizes of all contained components.
 731:    *
 732:    * @param p the container to be laid out.
 733:    * @return the maximum size of the container.
 734:    */
 735:   public Dimension maximumLayoutSize(Container p)
 736:   {
 737:     java.awt.Insets insets = p.getInsets();
 738: 
 739:     Constraints cs = initContainer(p);
 740: 
 741:     int maxX = cs.getWidth().getMaximumValue() + insets.left + insets.right;
 742:     int maxY = cs.getHeight().getMaximumValue() + insets.top + insets.bottom;
 743: 
 744:     return new Dimension(maxX, maxY);
 745:   }
 746: 
 747: 
 748:   /**
 749:    * Calculates the minimum size of the layed out container. This
 750:    * respects the minimum sizes of all contained components.
 751:    *
 752:    * @param p the container to be laid out.
 753:    * @return the minimum size of the container.
 754:    */
 755:   public Dimension minimumLayoutSize(Container p)
 756:   {
 757:     java.awt.Insets insets = p.getInsets();
 758: 
 759:     Constraints cs = initContainer(p);
 760: 
 761:     int maxX = cs.getWidth().getMinimumValue() + insets.left + insets.right;
 762:     int maxY = cs.getHeight().getMinimumValue() + insets.top + insets.bottom;
 763: 
 764:     return new Dimension(maxX, maxY);
 765:   }
 766: 
 767:   /**
 768:    * Calculates the preferred size of the layed out container. This
 769:    * respects the preferred sizes of all contained components.
 770:    *
 771:    * @param p the container to be laid out.
 772:    * @return the preferred size of the container.
 773:    */
 774:   public Dimension preferredLayoutSize(Container p)
 775:   {
 776:     java.awt.Insets insets = p.getInsets();
 777: 
 778:     Constraints cs = initContainer(p);
 779: 
 780:     int maxX = cs.getWidth().getPreferredValue() + insets.left + insets.right;
 781:     int maxY = cs.getHeight().getPreferredValue() + insets.top + insets.bottom;
 782: 
 783:     return new Dimension(maxX, maxY);
 784:   }
 785: 
 786:   /**
 787:    * Attaches the edge <code>e1</code> of component <code>c1</code> to
 788:    * the edge <code>e2</code> of component <code>c2</code> width the
 789:    * fixed strut <code>pad</code>.
 790:    *
 791:    * @param e1 the edge of component 1.
 792:    * @param c1 the component 1.
 793:    * @param pad the space between the components in pixels.
 794:    * @param e2 the edge of component 2.
 795:    * @param c2 the component 2.
 796:    */
 797:   public void putConstraint(String e1, Component c1, int pad, String e2, 
 798:                             Component c2)
 799:   {
 800:     putConstraint(e1, c1, Spring.constant(pad), e2, c2);
 801:   }
 802: 
 803:   /**
 804:    * Attaches the edge <code>e1</code> of component <code>c1</code> to
 805:    * the edge <code>e2</code> of component <code>c2</code> width the
 806:    * {@link Spring} <code>s</code>.
 807:    *
 808:    * @param e1 the edge of component 1.
 809:    * @param c1 the component 1.
 810:    * @param s the space between the components as a {@link Spring} object.
 811:    * @param e2 the edge of component 2.
 812:    * @param c2 the component 2.
 813:    */
 814:   public void putConstraint(String e1, Component c1, Spring s, String e2, 
 815:                             Component c2)
 816:   {
 817:     Constraints constraints1 = getConstraints(c1);
 818: 
 819:     Spring otherEdge = getConstraint(e2, c2);
 820:     constraints1.setConstraint(e1, Spring.sum(s, otherEdge));
 821: 
 822:   }
 823: 
 824:   /**
 825:    * Removes a layout component.
 826:    * @param c the layout component to remove.
 827:    */
 828:   public void removeLayoutComponent(Component c)
 829:   {
 830:     // do nothing here
 831:   }
 832: }