Source for java.awt.GridBagLayout

   1: /* GridBagLayout - Layout manager for components according to GridBagConstraints
   2:    Copyright (C) 2002, 2003, 2004, 2005, 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 java.awt;
  40: 
  41: import java.io.Serializable;
  42: import java.util.ArrayList;
  43: import java.util.HashMap;
  44: import java.util.Hashtable;
  45: 
  46: /**
  47:  * @author Michael Koch (konqueror@gmx.de)
  48:  * @author Jeroen Frijters (jeroen@frijters.net)
  49:  */
  50: public class GridBagLayout
  51:     implements Serializable, LayoutManager2
  52: {
  53:     private static final long serialVersionUID = 8838754796412211005L;
  54: 
  55:     protected static final int MINSIZE = 1;
  56:     protected static final int PREFERREDSIZE = 2;
  57:     protected static final int MAXGRIDSIZE = 512;
  58: 
  59:     // comptable remembers the original contraints given to us.
  60:     // internalcomptable is used to keep track of modified constraint values
  61:     // that we calculate, particularly when we are given RELATIVE and
  62:     // REMAINDER constraints.
  63:     // Constraints kept in comptable are never modified, and constraints
  64:     // kept in internalcomptable can be modified internally only.
  65:     protected Hashtable comptable;
  66:     private Hashtable internalcomptable;
  67:     protected GridBagLayoutInfo layoutInfo;
  68:     protected GridBagConstraints defaultConstraints;
  69: 
  70:     public double[] columnWeights;
  71:     public int[] columnWidths;
  72:     public double[] rowWeights;
  73:     public int[] rowHeights;
  74: 
  75:     public GridBagLayout ()
  76:     {
  77:     this.comptable = new Hashtable();
  78:     this.internalcomptable = new Hashtable();
  79:     this.defaultConstraints= new GridBagConstraints();
  80:     }
  81: 
  82:     /**
  83:      * Helper method to calc the sum of a range of elements in an int array.
  84:      */
  85:     private int sumIntArray (int[] array, int upto)
  86:     {
  87:     int result = 0;
  88: 
  89:     for (int i = 0; i < upto; i++)
  90:         result += array [i];
  91: 
  92:     return result;
  93:     }
  94: 
  95:     /**
  96:      * Helper method to calc the sum of all elements in an int array.
  97:      */
  98:     private int sumIntArray (int[] array)
  99:     {
 100:     return sumIntArray(array, array.length);
 101:     }
 102: 
 103:     /**
 104:      * Helper method to calc the sum of all elements in an double array.
 105:      */
 106:     private double sumDoubleArray (double[] array)
 107:     {
 108:     double result = 0;
 109: 
 110:     for (int i = 0; i < array.length; i++)
 111:         result += array [i];
 112: 
 113:     return result;
 114:     }
 115: 
 116:     public void addLayoutComponent (String name, Component component)
 117:     {
 118:     // do nothing here.
 119:     }
 120: 
 121:     public void removeLayoutComponent (Component component)
 122:     {
 123:     // do nothing here
 124:     }
 125: 
 126:     public void addLayoutComponent (Component component, Object constraints)
 127:     {
 128:     if (constraints == null)
 129:         return;
 130: 
 131:     if (!(constraints instanceof GridBagConstraints))
 132:         throw new IllegalArgumentException("constraints " 
 133:                            + constraints 
 134:                            + " are not an instance of GridBagConstraints");
 135: 
 136:     setConstraints (component, (GridBagConstraints) constraints);
 137:     }
 138: 
 139:     public Dimension preferredLayoutSize (Container parent)
 140:     {
 141:     if (parent == null)
 142:         return new Dimension (0, 0);
 143:     
 144:     GridBagLayoutInfo li = getLayoutInfo (parent, PREFERREDSIZE);
 145:     return getMinSize (parent, li);
 146:     }
 147: 
 148:     public Dimension minimumLayoutSize (Container parent)
 149:     {
 150:     if (parent == null)
 151:         return new Dimension (0, 0);
 152:     
 153:     GridBagLayoutInfo li = getLayoutInfo (parent, MINSIZE);
 154:     return getMinSize (parent, li);
 155:     }
 156: 
 157:     public Dimension maximumLayoutSize (Container target)
 158:     {
 159:     return new Dimension (Integer.MAX_VALUE, Integer.MAX_VALUE);
 160:     }
 161: 
 162:     public void layoutContainer (Container parent)
 163:     {
 164:       arrangeGrid (parent);
 165:     }
 166: 
 167:     public float getLayoutAlignmentX (Container target)
 168:     {
 169:     return Component.CENTER_ALIGNMENT;
 170:     }
 171: 
 172:     public float getLayoutAlignmentY (Container target)
 173:     {
 174:     return Component.CENTER_ALIGNMENT;
 175:     }
 176: 
 177:     public void invalidateLayout (Container target)
 178:     {
 179:     this.layoutInfo = null;
 180:     }
 181: 
 182:     public void setConstraints (Component component,
 183:     GridBagConstraints constraints)
 184:     {
 185:     GridBagConstraints clone = (GridBagConstraints) constraints.clone();
 186: 
 187:     if (clone.gridx < 0)
 188:         clone.gridx = GridBagConstraints.RELATIVE;
 189:     
 190:     if (clone.gridy < 0)
 191:         clone.gridy = GridBagConstraints.RELATIVE;
 192: 
 193:     if (clone.gridwidth == 0)
 194:         clone.gridwidth = GridBagConstraints.REMAINDER;
 195:     else if (clone.gridwidth < 0)
 196:         clone.gridwidth = 1;
 197:     
 198:     if (clone.gridheight == 0)
 199:         clone.gridheight = GridBagConstraints.REMAINDER;
 200:     else if (clone.gridheight < 0)
 201:         clone.gridheight = 1;
 202:     
 203:     comptable.put (component, clone);
 204:     }
 205: 
 206:     public GridBagConstraints getConstraints (Component component)
 207:     {
 208:     return (GridBagConstraints) (lookupConstraints (component).clone());
 209:     }
 210: 
 211:     protected GridBagConstraints lookupConstraints (Component component)
 212:     {
 213:     GridBagConstraints result = (GridBagConstraints) comptable.get (component);
 214: 
 215:     if (result == null)
 216:     {
 217:         setConstraints (component, defaultConstraints);
 218:         result = (GridBagConstraints) comptable.get (component);
 219:     }
 220:     
 221:     return result;
 222:     }
 223: 
 224:     private GridBagConstraints lookupInternalConstraints (Component component)
 225:     {
 226:     GridBagConstraints result =
 227:             (GridBagConstraints) internalcomptable.get (component);
 228: 
 229:     if (result == null)
 230:     {
 231:         result = (GridBagConstraints) lookupConstraints(component).clone();
 232:         internalcomptable.put (component, result);
 233:     }
 234:     
 235:     return result;
 236:     }
 237: 
 238:     /**
 239:      * @since 1.1
 240:      */
 241:     public Point getLayoutOrigin ()
 242:     {
 243:     if (layoutInfo == null)
 244:         return new Point (0, 0);
 245:     
 246:     return new Point (layoutInfo.pos_x, layoutInfo.pos_y);
 247:     }
 248: 
 249:     /**
 250:      * @since 1.1
 251:      */
 252:     public int[][] getLayoutDimensions ()
 253:     {
 254:     int[][] result = new int [2][];
 255:     if (layoutInfo == null)
 256:       {
 257:         result[0] = new int[0];
 258:         result[1] = new int[0];
 259: 
 260:         return result;
 261:       }
 262: 
 263:     result [0] = new int [layoutInfo.cols];
 264:     System.arraycopy (layoutInfo.colWidths, 0, result [0], 0, layoutInfo.cols);
 265:     result [1] = new int [layoutInfo.rows];
 266:     System.arraycopy (layoutInfo.rowHeights, 0, result [1], 0, layoutInfo.rows);
 267:     return result;
 268:     }
 269: 
 270:     public double[][] getLayoutWeights ()
 271:     {
 272:     double[][] result = new double [2][];
 273:     if (layoutInfo == null)
 274:       {
 275:         result[0] = new double[0];
 276:         result[1] = new double[0];
 277: 
 278:         return result;
 279:       }
 280: 
 281:     result [0] = new double [layoutInfo.cols];
 282:     System.arraycopy (layoutInfo.colWeights, 0, result [0], 0, layoutInfo.cols);
 283:     result [1] = new double [layoutInfo.rows];
 284:     System.arraycopy (layoutInfo.rowWeights, 0, result [1], 0, layoutInfo.rows);
 285:     return result;
 286:     }
 287: 
 288:     /**
 289:      * @since 1.1
 290:      */
 291:     public Point location (int x, int y)
 292:     {
 293:     if (layoutInfo == null)
 294:         return new Point (0, 0);
 295: 
 296:     int col;
 297:     int row;
 298:     int pixel_x = layoutInfo.pos_x;
 299:     int pixel_y = layoutInfo.pos_y;
 300: 
 301:     for (col = 0; col < layoutInfo.cols; col++)
 302:     {
 303:         int w = layoutInfo.colWidths [col];
 304:         if (x < pixel_x + w)
 305:         break;
 306: 
 307:         pixel_x += w;
 308:     }
 309: 
 310:     for (row = 0; row < layoutInfo.rows; row++)
 311:     {
 312:         int h = layoutInfo.rowHeights [row];
 313:         if (y < pixel_y + h)
 314:         break;
 315: 
 316:         pixel_y += h;
 317:     }
 318: 
 319:     return new Point (col, row);
 320:     }
 321: 
 322:     /**
 323:      * Move and resize a rectangle according to a set of grid bag
 324:      * constraints.  The x, y, width and height fields of the
 325:      * rectangle argument are adjusted to the new values.
 326:      *
 327:      * @param constraints position and size constraints
 328:      * @param r rectangle to be moved and resized
 329:      */
 330:     protected void AdjustForGravity (GridBagConstraints constraints,
 331:                                      Rectangle r)
 332:     {
 333:       Insets insets = constraints.insets;
 334:       if (insets != null)
 335:     {
 336:       r.x += insets.left;
 337:       r.y += insets.top;
 338:       r.width -= insets.left + insets.right;
 339:       r.height -= insets.top + insets.bottom;
 340:     }
 341:     }
 342: 
 343:     /**
 344:      * Obsolete.
 345:      */
 346:     protected void ArrangeGrid (Container parent)
 347:     {
 348:       Component[] components = parent.getComponents();
 349: 
 350:       if (components.length == 0)
 351:         return;
 352: 
 353:       GridBagLayoutInfo info = getLayoutInfo (parent, PREFERREDSIZE);
 354:       if (info.cols == 0 && info.rows == 0)
 355:         return;
 356: 
 357:       // DEBUG
 358:       //dumpLayoutInfo (info);
 359: 
 360:       // Calling setBounds on these components causes this layout to
 361:       // be invalidated, clearing the layout information cache,
 362:       // layoutInfo.  So we wait until after this for loop to set
 363:       // layoutInfo.
 364:       Component lastComp = null;
 365: 
 366:       Rectangle cell = new Rectangle();
 367: 
 368:       for (int i = 0; i < components.length; i++)
 369:       {
 370:         Component component = components[i];
 371: 
 372:         // If component is not visible we dont have to care about it.
 373:         if (! component.isVisible())
 374:           continue;
 375: 
 376:         Dimension dim = component.getPreferredSize();
 377:         GridBagConstraints constraints = lookupInternalConstraints(component);
 378:         
 379:         if (lastComp != null
 380:             && constraints.gridheight == GridBagConstraints.REMAINDER)
 381:           cell.y += cell.height;
 382:         else
 383:           cell.y = sumIntArray(info.rowHeights, constraints.gridy);
 384:         
 385:         if (lastComp != null
 386:             && constraints.gridwidth == GridBagConstraints.REMAINDER)
 387:           cell.x += cell.width;
 388:         else
 389:           cell.x = sumIntArray(info.colWidths, constraints.gridx);
 390: 
 391:         cell.width = sumIntArray(info.colWidths, constraints.gridx
 392:                                             + constraints.gridwidth) - cell.x;
 393:         cell.height = sumIntArray(info.rowHeights, constraints.gridy
 394:                                              + constraints.gridheight) - cell.y;
 395:     
 396:         // Adjust for insets.
 397:      AdjustForGravity( constraints, cell );
 398: 
 399:         // Note: Documentation says that padding is added on both sides, but
 400:         // visual inspection shows that the Sun implementation only adds it
 401:         // once, so we do the same.
 402:         dim.width += constraints.ipadx;
 403:         dim.height += constraints.ipady;
 404: 
 405:         switch (constraints.fill)
 406:           {
 407:           case GridBagConstraints.HORIZONTAL:
 408:             dim.width = cell.width;
 409:             break;
 410:           case GridBagConstraints.VERTICAL:
 411:             dim.height = cell.height;
 412:             break;
 413:           case GridBagConstraints.BOTH:
 414:             dim.width = cell.width;
 415:             dim.height = cell.height;
 416:             break;
 417:           }
 418: 
 419:         int x = 0;
 420:         int y = 0;
 421: 
 422:         switch (constraints.anchor)
 423:           {
 424:           case GridBagConstraints.NORTH:
 425:             x = cell.x + (cell.width - dim.width) / 2;
 426:             y = cell.y;
 427:             break;
 428:           case GridBagConstraints.SOUTH:
 429:             x = cell.x + (cell.width - dim.width) / 2;
 430:             y = cell.y + cell.height - dim.height;
 431:             break;
 432:           case GridBagConstraints.WEST:
 433:             x = cell.x;
 434:             y = cell.y + (cell.height - dim.height) / 2;
 435:             break;
 436:           case GridBagConstraints.EAST:
 437:             x = cell.x + cell.width - dim.width;
 438:             y = cell.y + (cell.height - dim.height) / 2;
 439:             break;
 440:           case GridBagConstraints.NORTHEAST:
 441:             x = cell.x + cell.width - dim.width;
 442:             y = cell.y;
 443:             break;
 444:           case GridBagConstraints.NORTHWEST:
 445:             x = cell.x;
 446:             y = cell.y;
 447:             break;
 448:           case GridBagConstraints.SOUTHEAST:
 449:             x = cell.x + cell.width - dim.width;
 450:             y = cell.y + cell.height - dim.height;
 451:             break;
 452:           case GridBagConstraints.SOUTHWEST:
 453:             x = cell.x;
 454:             y = cell.y + cell.height - dim.height;
 455:             break;
 456:           default:
 457:             x = cell.x + (cell.width - dim.width) / 2;
 458:             y = cell.y + (cell.height - dim.height) / 2;
 459:             break;
 460:           }
 461:         component.setBounds(info.pos_x + x, info.pos_y + y, dim.width,
 462:                             dim.height);
 463:         lastComp = component;
 464:       }
 465: 
 466:     // DEBUG
 467:     //dumpLayoutInfo(info);
 468: 
 469:     // Cache layout information.
 470:     layoutInfo = getLayoutInfo(parent, PREFERREDSIZE);
 471:   }
 472: 
 473:     /**
 474:      * Obsolete.
 475:      */
 476:     protected GridBagLayoutInfo GetLayoutInfo (Container parent, int sizeflag)
 477:     {
 478:       if (sizeflag != MINSIZE && sizeflag != PREFERREDSIZE)
 479:         throw new IllegalArgumentException();
 480: 
 481:       Dimension parentDim = parent.getSize ();
 482:       Insets parentInsets = parent.getInsets ();
 483:       parentDim.width -= parentInsets.left + parentInsets.right;
 484:       parentDim.height -= parentInsets.top + parentInsets.bottom;
 485:    
 486:       int current_y = 0;
 487:       int max_x = 0;
 488:       int max_y = 0;
 489: 
 490:       // Guaranteed to contain the last component added to the given row
 491:       // or column, whose gridwidth/height is not REMAINDER.
 492:       HashMap lastInRow = new HashMap();
 493:       HashMap lastInCol = new HashMap();
 494: 
 495:       Component[] components = parent.getComponents();
 496: 
 497:       // Components sorted by gridwidths/heights,
 498:       // smallest to largest, with REMAINDER and RELATIVE at the end.
 499:       // These are useful when determining sizes and weights.
 500:       ArrayList sortedByWidth = new ArrayList(components.length);
 501:       ArrayList sortedByHeight = new ArrayList(components.length);
 502: 
 503:       // STEP 1: first we figure out how many rows/columns
 504:       for (int i = 0; i < components.length; i++)
 505:     {
 506:           Component component = components [i];
 507:           // If component is not visible we dont have to care about it.
 508:           if (!component.isVisible())
 509:             continue;
 510: 
 511:           // When looking up the constraint for the first time, check the
 512:           // original unmodified constraint.  After the first time, always
 513:           // refer to the internal modified constraint.
 514:           GridBagConstraints originalConstraints = lookupConstraints (component);
 515:           GridBagConstraints constraints = (GridBagConstraints) originalConstraints.clone();
 516:           internalcomptable.put(component, constraints);
 517: 
 518:           // Cases:
 519:           //
 520:           // 1. gridy == RELATIVE, gridx == RELATIVE
 521:           //
 522:           //       use y as the row number; check for the next
 523:           //       available slot at row y
 524:           //
 525:           // 2. only gridx == RELATIVE
 526:           //
 527:           //       check for the next available slot at row gridy
 528:           //
 529:           // 3. only gridy == RELATIVE
 530:           //
 531:           //       check for the next available slot at column gridx
 532:           //
 533:           // 4. neither gridx or gridy == RELATIVE
 534:           //
 535:           //       nothing to check; just add it
 536: 
 537:           // cases 1 and 2
 538:           if(constraints.gridx == GridBagConstraints.RELATIVE)
 539:             {
 540:               if (constraints.gridy == GridBagConstraints.RELATIVE)
 541:               constraints.gridy = current_y;
 542: 
 543:               int x;
 544: 
 545:               // Check the component that occupies the right-most spot in this
 546:               // row. We want to add this component after it.
 547:               // If this row is empty, add to the 0 position.
 548:               if (!lastInRow.containsKey(new Integer(constraints.gridy))) 
 549:                 x = 0;
 550:               else
 551:                 {
 552:                   Component lastComponent = (Component) lastInRow.get(new Integer(constraints.gridy));
 553:                   GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent);
 554:                   x = lastConstraints.gridx + Math.max(1, lastConstraints.gridwidth);
 555:                 }
 556: 
 557:               // Determine if this component will fit in the slot vertically.
 558:               // If not, bump it over to where it does fit.
 559:               for (int y = constraints.gridy + 1; y < constraints.gridy + Math.max(1, constraints.gridheight); y++)
 560:                 {
 561:                   if (lastInRow.containsKey(new Integer(y)))
 562:                     {
 563:                       Component lastComponent = (Component) lastInRow.get(new Integer(y));
 564:                       GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent);
 565:                       x = Math.max (x,
 566:                                     lastConstraints.gridx + Math.max(1, lastConstraints.gridwidth));
 567:                     }
 568:                 }
 569: 
 570:               constraints.gridx = x;
 571:             }
 572:           // case 3
 573:           else if(constraints.gridy == GridBagConstraints.RELATIVE)
 574:             {
 575:               int y;
 576:               // Check the component that occupies the bottom-most spot in
 577:               // this column. We want to add this component below it.
 578:               // If this column is empty, add to the 0 position.
 579:               if (!lastInCol.containsKey(new Integer(constraints.gridx))) 
 580:                 {
 581:                   y = current_y;
 582:                 }
 583:               else
 584:                 {
 585:                   Component lastComponent = (Component)lastInCol.get(new Integer(constraints.gridx));
 586:                   GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent);
 587:                   y = lastConstraints.gridy + Math.max(1, lastConstraints.gridheight);
 588:                 }
 589: 
 590:               // Determine if this component will fit in the slot horizontally.
 591:               // If not, bump it down to where it does fit.
 592:               for (int x = constraints.gridx + 1; x < constraints.gridx + Math.max(1, constraints.gridwidth); x++)
 593:                 {
 594:                   if (lastInCol.containsKey(new Integer(x)))
 595:                     {
 596:                       Component lastComponent = (Component) lastInCol.get(new Integer(x));
 597:                       GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent);
 598:                       y = Math.max (y,
 599:                                     lastConstraints.gridy + Math.max(1, lastConstraints.gridheight));
 600:                     }
 601:                 }
 602: 
 603:               constraints.gridy = y;
 604:             }
 605:           // case 4: do nothing
 606: 
 607:           max_x = Math.max(max_x, 
 608:                            constraints.gridx + Math.max(1, constraints.gridwidth));
 609:           max_y = Math.max(max_y,
 610:                            constraints.gridy + Math.max(1, constraints.gridheight));
 611: 
 612:           sortBySpan(component, constraints.gridwidth, sortedByWidth, true);
 613:           sortBySpan(component, constraints.gridheight, sortedByHeight, false);
 614: 
 615:           // Update our reference points for RELATIVE gridx and gridy.
 616:           if(constraints.gridwidth == GridBagConstraints.REMAINDER)
 617:         {
 618:           current_y = constraints.gridy + Math.max(1, constraints.gridheight);
 619:         }
 620:           else if (constraints.gridwidth != GridBagConstraints.REMAINDER)
 621:         {
 622:               for (int y = constraints.gridy; y < constraints.gridy + Math.max(1, constraints.gridheight); y++)
 623:                 {
 624:                   if(lastInRow.containsKey(new Integer(y)))
 625:                     {
 626:                       Component lastComponent = (Component) lastInRow.get(new Integer(y));
 627:                       GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent);
 628:                       if (constraints.gridx > lastConstraints.gridx)
 629:                         {
 630:                           lastInRow.put(new Integer(y), component);
 631:                         }
 632:                     }
 633:                   else
 634:                     {
 635:                       lastInRow.put(new Integer(y), component);
 636:                     }
 637:                 }
 638: 
 639:               for (int x = constraints.gridx; x < constraints.gridx + Math.max(1, constraints.gridwidth); x++)
 640:                 {
 641:                   if(lastInCol.containsKey(new Integer(x)))
 642:                     {
 643:                       Component lastComponent = (Component) lastInCol.get(new Integer(x));
 644:                       GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent);
 645:                       if (constraints.gridy > lastConstraints.gridy)
 646:                         {
 647:                           lastInCol.put(new Integer(x), component);
 648:                         }
 649:                     }
 650:                   else
 651:                     {
 652:                       lastInCol.put(new Integer(x), component);
 653:                     }
 654:                 }
 655:         }
 656:     } // end of STEP 1
 657:     
 658:       GridBagLayoutInfo info = new GridBagLayoutInfo(max_x, max_y);
 659: 
 660:       // Check if column widths and row heights are overridden.
 661: 
 662:       for (int x = 0; x < max_x; x++)
 663:         {
 664:           if(columnWidths != null && columnWidths.length > x)
 665:             info.colWidths[x] = columnWidths[x];
 666:           if(columnWeights != null && columnWeights.length > x)
 667:             info.colWeights[x] = columnWeights[x];
 668:         }
 669: 
 670:       for (int y = 0; y < max_y; y++)
 671:         {
 672:           if(rowHeights != null && rowHeights.length > y)
 673:             info.rowHeights[y] = rowHeights[y];
 674:           if(rowWeights != null && rowWeights.length > y)
 675:             info.rowWeights[y] = rowWeights[y];
 676:         }
 677: 
 678:       // STEP 2: Fix up any cells with width/height as REMAINDER/RELATIVE.
 679:       for (int i = 0; i < components.length; i++)
 680:         {
 681:           Component component = components [i];
 682:             
 683:           // If component is not visible we dont have to care about it.
 684:           if (!component.isVisible())
 685:             continue;
 686:             
 687:           GridBagConstraints constraints = lookupInternalConstraints (component);
 688: 
 689:           if(constraints.gridwidth == GridBagConstraints.REMAINDER || constraints.gridwidth == GridBagConstraints.RELATIVE)
 690:             {
 691:               if(constraints.gridwidth == GridBagConstraints.REMAINDER)
 692:                 {
 693:                   for (int y = constraints.gridy; y < constraints.gridy + Math.max(1, constraints.gridheight); y++)
 694:                     {
 695:                       if (lastInRow.containsKey(new Integer(y)))
 696:                         {
 697:                           Component lastComponent = (Component) lastInRow.get(new Integer(y));
 698:                           GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent);
 699: 
 700:                           if (lastConstraints.gridwidth == GridBagConstraints.RELATIVE)
 701:                             {
 702:                               constraints.gridx = max_x - 1;
 703:                               break;
 704:                             }
 705:                           else
 706:                             {
 707:                               constraints.gridx = Math.max (constraints.gridx,
 708:                                                             lastConstraints.gridx + Math.max (1, lastConstraints.gridwidth));
 709:                             }
 710:                         }
 711:                     }
 712:                   constraints.gridwidth = max_x - constraints.gridx;
 713:                 }
 714:               else if (constraints.gridwidth == GridBagConstraints.RELATIVE)
 715:                 {
 716:                   constraints.gridwidth = max_x - constraints.gridx - 1;
 717:                 }
 718: 
 719:               // Re-sort
 720:               sortedByWidth.remove(sortedByWidth.indexOf(component));
 721:               sortBySpan(component, constraints.gridwidth, sortedByWidth, true);
 722:             }
 723: 
 724:           if(constraints.gridheight == GridBagConstraints.REMAINDER || constraints.gridheight == GridBagConstraints.RELATIVE)
 725:             {
 726:               if(constraints.gridheight == GridBagConstraints.REMAINDER)
 727:                 {
 728:                   for (int x = constraints.gridx; x < constraints.gridx + Math.max(1, constraints.gridwidth); x++)
 729:                     {
 730:                       if (lastInCol.containsKey(new Integer(x)))
 731:                         {
 732:                           Component lastComponent = (Component) lastInRow.get(new Integer(x));
 733:                           if (lastComponent != null)
 734:                             {
 735:                               GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent);
 736:     
 737:                               if (lastConstraints.gridheight == GridBagConstraints.RELATIVE)
 738:                                 {
 739:                                   constraints.gridy = max_y - 1;
 740:                                   break;
 741:                                 }
 742:                               else
 743:                                 {
 744:                                   constraints.gridy = Math.max (constraints.gridy,
 745:                                                                 lastConstraints.gridy + Math.max (1, lastConstraints.gridheight));
 746:                                 }
 747:                             }
 748:                         }
 749:                     }
 750:                   constraints.gridheight = max_y - constraints.gridy;
 751:                 }
 752:               else if (constraints.gridheight == GridBagConstraints.RELATIVE)
 753:                 {
 754:                   constraints.gridheight = max_y - constraints.gridy - 1;
 755:                 }
 756: 
 757:               // Re-sort
 758:               sortedByHeight.remove(sortedByHeight.indexOf(component));
 759:               sortBySpan(component, constraints.gridheight, sortedByHeight, false);
 760:             }
 761:         } // end of STEP 2
 762: 
 763:       // STEP 3: Determine sizes and weights for columns.
 764:       for (int i = 0; i < sortedByWidth.size(); i++)
 765:         {
 766:           Component component = (Component) sortedByWidth.get(i);
 767:             
 768:           // If component is not visible we dont have to care about it.
 769:           if (!component.isVisible())
 770:             continue;
 771: 
 772:           GridBagConstraints constraints = lookupInternalConstraints (component);
 773: 
 774:           int width = (sizeflag == PREFERREDSIZE) ?
 775:                       component.getPreferredSize().width :
 776:                       component.getMinimumSize().width;
 777: 
 778:           if(constraints.insets != null)
 779:             width += constraints.insets.left + constraints.insets.right;
 780: 
 781:           width += constraints.ipadx;
 782: 
 783:           distributeSizeAndWeight(width,
 784:                                   constraints.weightx, 
 785:                                   constraints.gridx,
 786:                                   constraints.gridwidth,
 787:                                   info.colWidths,
 788:                                   info.colWeights);
 789:         } // end of STEP 3
 790: 
 791:       // STEP 4: Determine sizes and weights for rows.
 792:       for (int i = 0; i < sortedByHeight.size(); i++)
 793:         {
 794:           Component component = (Component) sortedByHeight.get(i);
 795:             
 796:           // If component is not visible we dont have to care about it.
 797:           if (!component.isVisible())
 798:             continue;
 799: 
 800:           GridBagConstraints constraints = lookupInternalConstraints (component);
 801: 
 802:           int height = (sizeflag == PREFERREDSIZE) ?
 803:                        component.getPreferredSize().height :
 804:                        component.getMinimumSize().height;
 805: 
 806:           if(constraints.insets != null)
 807:             height += constraints.insets.top + constraints.insets.bottom;
 808: 
 809:           height += constraints.ipady;
 810:           
 811:           distributeSizeAndWeight(height,
 812:                                   constraints.weighty, 
 813:                                   constraints.gridy,
 814:                                   constraints.gridheight,
 815:                                   info.rowHeights,
 816:                                   info.rowWeights);
 817:         } // end of STEP 4
 818: 
 819:       // Adjust cell sizes iff parent size not zero.
 820:       if (parentDim.width > 0 && parentDim.height > 0)
 821:         {
 822:           calcCellSizes (info.colWidths, info.colWeights, parentDim.width);
 823:           calcCellSizes (info.rowHeights, info.rowWeights, parentDim.height);
 824:         }
 825: 
 826:       int totalWidth = sumIntArray(info.colWidths);
 827:       int totalHeight = sumIntArray(info.rowHeights);
 828: 
 829:       // Make sure pos_x and pos_y are never negative.
 830:       if (totalWidth >= parentDim.width)
 831:         info.pos_x = parentInsets.left;
 832:       else
 833:         info.pos_x = parentInsets.left + (parentDim.width - totalWidth) / 2;
 834: 
 835:       if (totalHeight >= parentDim.height)
 836:         info.pos_y = parentInsets.top;
 837:       else
 838:         info.pos_y = parentInsets.top + (parentDim.height - totalHeight) / 2;
 839: 
 840:       // DEBUG
 841:       //dumpLayoutInfo (info);
 842: 
 843:       return info;
 844:     }
 845: 
 846:     /**
 847:      * Obsolete.
 848:      */
 849:     protected Dimension GetMinSize (Container parent, GridBagLayoutInfo info)
 850:     {
 851:       if (parent == null || info == null)
 852:         return new Dimension (0, 0);
 853: 
 854:       Insets insets = parent.getInsets();
 855:       int width = sumIntArray (info.colWidths) + insets.left + insets.right;
 856:       int height = sumIntArray (info.rowHeights) + insets.top + insets.bottom;
 857:       return new Dimension (width, height);
 858:     }
 859: 
 860:     /**
 861:      * @since 1.4
 862:      */
 863:     protected Dimension getMinSize (Container parent, GridBagLayoutInfo info)
 864:     {
 865:       return GetMinSize (parent, info);
 866:     }
 867: 
 868:     /**
 869:      * Helper method used by GetLayoutInfo to keep components sorted, either
 870:      * by gridwidth or gridheight.
 871:      *
 872:      * @param component   Component to add to the sorted list.
 873:      * @param span        Either the component's gridwidth or gridheight.
 874:      * @param list        <code>ArrayList</code> of components, sorted by
 875:      *                    their span.
 876:      * @param sortByWidth Flag indicating sorting index. If true, sort by
 877:      *                    width. Otherwise, sort by height.
 878:      * FIXME: Use a better sorting algorithm.
 879:      */
 880:     private void sortBySpan (Component component, int span, ArrayList list, boolean sortByWidth)
 881:     {
 882:       if (span == GridBagConstraints.REMAINDER
 883:           || span == GridBagConstraints.RELATIVE)
 884:         {
 885:           // Put all RELATIVE and REMAINDER components at the end.
 886:           list.add(component);
 887:         }
 888:       else
 889:         {
 890:           int i = 0;
 891:           if (list.size() > 0)
 892:             {
 893:               GridBagConstraints gbc = lookupInternalConstraints((Component) list.get(i));
 894:               int otherspan = sortByWidth ?
 895:                               gbc.gridwidth :
 896:                               gbc.gridheight;
 897:               while (otherspan != GridBagConstraints.REMAINDER
 898:                      && otherspan != GridBagConstraints.RELATIVE
 899:                      && span >= otherspan)
 900:                 {
 901:                   i++;
 902:                   if (i < list.size())
 903:                     {
 904:                       gbc = lookupInternalConstraints((Component) list.get(i));
 905:                       otherspan = sortByWidth ?
 906:                                   gbc.gridwidth :
 907:                                   gbc.gridheight;
 908:                     }
 909:                   else
 910:                     break;
 911:                 }
 912:             }
 913:           list.add(i, component);
 914:         }
 915:     }
 916: 
 917:     /**
 918:      * Helper method used by GetLayoutInfo to distribute a component's size
 919:      * and weight.
 920:      *
 921:      * @param size    Preferred size of component, with inset and padding
 922:      *                already added.
 923:      * @param weight  Weight of component.
 924:      * @param start   Starting position of component. Either
 925:      *                constraints.gridx or gridy.
 926:      * @param span    Span of component. either contraints.gridwidth or
 927:      *                gridheight.
 928:      * @param sizes   Sizes of rows or columns.
 929:      * @param weights Weights of rows or columns.
 930:      */
 931:     private void distributeSizeAndWeight (int size, double weight,
 932:                                           int start, int span,
 933:                                           int[] sizes, double[] weights)
 934:     {
 935:       if (span == 1)
 936:         {
 937:           sizes[start] = Math.max(sizes[start], size);
 938:           weights[start] = Math.max(weights[start], weight);
 939:         }
 940:       else
 941:         {
 942:           int numOccupied = span;
 943:           int lastOccupied = -1;
 944: 
 945:           for(int i = start; i < start + span; i++)
 946:             {
 947:               if (sizes[i] == 0.0)
 948:                 numOccupied--;
 949:               else
 950:                 {
 951:                   size -= sizes[i];
 952:                   lastOccupied = i;
 953:                 }
 954:             }
 955: 
 956:           // A component needs to occupy at least one row.
 957:           if(numOccupied == 0)
 958:             sizes[start + span - 1] = size;
 959:           else if (size > 0)
 960:             sizes[lastOccupied] += size;
 961: 
 962:           calcCellWeights(weight, weights, start, span);
 963:         }
 964:     }
 965: 
 966:     /**
 967:      * Helper method used by GetLayoutInfo to calculate weight distribution.
 968:      * @param weight  Weight of component.
 969:      * @param weights Weights of rows/columns.
 970:      * @param start   Starting position of component in grid (gridx/gridy).
 971:      * @param span    Span of component (gridwidth/gridheight).
 972:      */
 973:     private void calcCellWeights (double weight, double[] weights, int start, int span)
 974:     {
 975:       double totalWeight = 0.0;
 976:       for(int k = start; k < start + span; k++)
 977:         totalWeight += weights[k];
 978: 
 979:       if(weight > totalWeight)
 980:         {
 981:           if (totalWeight == 0.0)
 982:             {
 983:               weights[start + span - 1] += weight;
 984:             }
 985:           else
 986:             {
 987:               double diff = weight - totalWeight ;
 988:               double remaining = diff;
 989: 
 990:               for(int k = start; k < start + span; k++)
 991:                 {
 992:                   double extraWeight = diff * weights[k] / totalWeight;
 993:                   weights[k] += extraWeight;
 994:                   remaining -= extraWeight;
 995:                 } 
 996: 
 997:               if (remaining > 0.0 && weights[start + span - 1] != 0.0)
 998:                 {
 999:                   weights[start + span - 1] += remaining;
1000:                 }
1001:             }
1002:         }
1003:     }
1004: 
1005:     /**
1006:      * Helper method used by GetLayoutInfo to distribute extra space
1007:      * based on weight distribution.
1008:      *
1009:      * @param sizes   Sizes of rows/columns.
1010:      * @param weights Weights of rows/columns.
1011:      * @param range   Dimension of container.
1012:      */
1013:     private void calcCellSizes (int[] sizes, double[] weights, int range)
1014:     {
1015:       int totalSize = sumIntArray (sizes);
1016:       double totalWeight = sumDoubleArray (weights);
1017: 
1018:       int diff = range - totalSize;
1019: 
1020:       if (diff == 0)
1021:         return;
1022: 
1023:       for (int i = 0; i < sizes.length; i++)
1024:         {
1025:           int newsize = (int) (sizes[i] + (((double) diff) * weights [i] / totalWeight ));
1026: 
1027:           if (newsize > 0)
1028:             sizes[i] = newsize;
1029:         }
1030:     }
1031: 
1032:     private void dumpLayoutInfo (GridBagLayoutInfo info)
1033:     {
1034:     System.out.println ("GridBagLayoutInfo:");
1035:     System.out.println ("cols: " + info.cols + ", rows: " + info.rows);
1036:     System.out.print ("colWidths: ");
1037:     dumpArray(info.colWidths);
1038:     System.out.print ("rowHeights: ");
1039:     dumpArray(info.rowHeights);
1040:     System.out.print ("colWeights: ");
1041:     dumpArray(info.colWeights);
1042:     System.out.print ("rowWeights: ");
1043:     dumpArray(info.rowWeights);
1044:     }
1045: 
1046:     private void dumpArray(int[] array)
1047:     {
1048:     String sep = "";
1049:     for(int i = 0; i < array.length; i++)
1050:     {
1051:         System.out.print(sep);
1052:         System.out.print(array[i]);
1053:         sep = ", ";
1054:     }
1055:     System.out.println();
1056:     }
1057: 
1058:     private void dumpArray(double[] array)
1059:     {
1060:     String sep = "";
1061:     for(int i = 0; i < array.length; i++)
1062:     {
1063:         System.out.print(sep);
1064:         System.out.print(array[i]);
1065:         sep = ", ";
1066:     }
1067:     System.out.println();
1068:     }
1069:   
1070:     /**
1071:      * @since 1.4
1072:      */
1073:     protected void arrangeGrid (Container parent)
1074:     {
1075:       ArrangeGrid (parent);
1076:     }
1077: 
1078:     /**
1079:      * @since 1.4
1080:      */
1081:     protected GridBagLayoutInfo getLayoutInfo (Container parent, int sizeflag)
1082:     {
1083:       return GetLayoutInfo (parent, sizeflag);
1084:     }
1085: 
1086:     /**
1087:      * Move and resize a rectangle according to a set of grid bag
1088:      * constraints.  The x, y, width and height fields of the
1089:      * rectangle argument are adjusted to the new values.
1090:      *
1091:      * @param constraints position and size constraints
1092:      * @param r rectangle to be moved and resized
1093:      *
1094:      * @since 1.4
1095:      */
1096:     protected void adjustForGravity (GridBagConstraints constraints,
1097:                                      Rectangle r)
1098:     {
1099:       AdjustForGravity (constraints, r);
1100:     }
1101: }