Source for java.awt.GridBagLayout

   1: /* GridBagLayout - Layout manager for components according to GridBagConstraints
   2:    Copyright (C) 2002, 2003, 2004, 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: 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:      * Obsolete.
 324:      */
 325:     protected void AdjustForGravity (GridBagConstraints gbc, Rectangle rect)
 326:     {
 327:       // FIXME
 328:       throw new Error ("Not implemented");
 329:     }
 330: 
 331:     /**
 332:      * Obsolete.
 333:      */
 334:     protected void ArrangeGrid (Container parent)
 335:     {
 336:       Component[] components = parent.getComponents();
 337: 
 338:       if (components.length == 0)
 339:         return;
 340: 
 341:       GridBagLayoutInfo info = getLayoutInfo (parent, PREFERREDSIZE);
 342:       if (info.cols == 0 && info.rows == 0)
 343:         return;
 344: 
 345:       // DEBUG
 346:       //dumpLayoutInfo (info);
 347: 
 348:       // Calling setBounds on these components causes this layout to
 349:       // be invalidated, clearing the layout information cache,
 350:       // layoutInfo.  So we wait until after this for loop to set
 351:       // layoutInfo.
 352:       for(int i = 0; i < components.length; i++)
 353:     {
 354:           Component component = components [i];
 355:         
 356:           // If component is not visible we dont have to care about it.
 357:           if (!component.isVisible())
 358:             continue;
 359:         
 360:           GridBagConstraints constraints =
 361:               lookupInternalConstraints(component);
 362: 
 363:           int cellx = sumIntArray(info.colWidths, constraints.gridx);
 364:           int celly = sumIntArray(info.rowHeights, constraints.gridy);
 365:           int cellw = sumIntArray(info.colWidths,
 366:                                   constraints.gridx + constraints.gridwidth) - cellx;
 367:           int cellh = sumIntArray(info.rowHeights,
 368:                                   constraints.gridy + constraints.gridheight) - celly;
 369: 
 370:           Insets insets = constraints.insets;
 371:           if (insets != null)
 372:         {
 373:               cellx += insets.left;
 374:               celly += insets.top;
 375:               cellw -= insets.left + insets.right;
 376:               cellh -= insets.top + insets.bottom;
 377:         }
 378: 
 379:           Dimension dim = component.getPreferredSize();
 380: 
 381:           // Note: Documentation says that padding is added on both sides, but
 382:           // visual inspection shows that the Sun implementation only adds it
 383:           // once, so we do the same.
 384:           dim.width += constraints.ipadx;
 385:           dim.height += constraints.ipady;
 386: 
 387:           switch(constraints.fill)
 388:         {
 389:             case GridBagConstraints.HORIZONTAL:
 390:               dim.width = cellw;
 391:               break;
 392:             case GridBagConstraints.VERTICAL:
 393:               dim.height = cellh;
 394:               break;
 395:             case GridBagConstraints.BOTH:
 396:               dim.width = cellw;
 397:               dim.height = cellh;
 398:               break;
 399:         }
 400: 
 401:           int x;
 402:           int y;
 403: 
 404:           switch(constraints.anchor)
 405:         {
 406:             case GridBagConstraints.NORTH:
 407:               x = cellx + (cellw - dim.width) / 2;
 408:               y = celly;
 409:               break;
 410:             case GridBagConstraints.SOUTH:
 411:               x = cellx + (cellw - dim.width) / 2;
 412:               y = celly + cellh - dim.height;
 413:               break;
 414:             case GridBagConstraints.WEST:
 415:               x = cellx;
 416:               y = celly + (cellh - dim.height) / 2;
 417:               break;
 418:             case GridBagConstraints.EAST:
 419:               x = cellx + cellw - dim.width;
 420:               y = celly + (cellh - dim.height) / 2;
 421:               break;
 422:             case GridBagConstraints.NORTHEAST:
 423:               x = cellx + cellw - dim.width;
 424:               y = celly;
 425:               break;
 426:             case GridBagConstraints.NORTHWEST:
 427:               x = cellx;
 428:               y = celly;
 429:               break;
 430:             case GridBagConstraints.SOUTHEAST:
 431:               x = cellx + cellw - dim.width;
 432:               y = celly + cellh - dim.height;
 433:               break;
 434:             case GridBagConstraints.SOUTHWEST:
 435:               x = cellx;
 436:               y = celly + cellh - dim.height;
 437:               break;
 438:             default:
 439:               x = cellx + (cellw - dim.width) / 2;
 440:               y = celly + (cellh - dim.height) / 2;
 441:               break;
 442:         }
 443: 
 444:           component.setBounds(info.pos_x + x, info.pos_y + y, dim.width, dim.height);
 445:     }
 446: 
 447:       // DEBUG
 448:       //dumpLayoutInfo (info);
 449: 
 450:       // Cache layout information.
 451:       layoutInfo = getLayoutInfo (parent, PREFERREDSIZE);
 452:     }
 453: 
 454:     /**
 455:      * Obsolete.
 456:      */
 457:     protected GridBagLayoutInfo GetLayoutInfo (Container parent, int sizeflag)
 458:     {
 459:       if (sizeflag != MINSIZE && sizeflag != PREFERREDSIZE)
 460:         throw new IllegalArgumentException();
 461: 
 462:       Dimension parentDim = parent.getSize ();
 463:       Insets parentInsets = parent.getInsets ();
 464:       parentDim.width -= parentInsets.left + parentInsets.right;
 465:       parentDim.height -= parentInsets.top + parentInsets.bottom;
 466:    
 467:       int current_y = 0;
 468:       int max_x = 0;
 469:       int max_y = 0;
 470: 
 471:       // Guaranteed to contain the last component added to the given row
 472:       // or column, whose gridwidth/height is not REMAINDER.
 473:       HashMap lastInRow = new HashMap();
 474:       HashMap lastInCol = new HashMap();
 475: 
 476:       Component[] components = parent.getComponents();
 477: 
 478:       // Components sorted by gridwidths/heights,
 479:       // smallest to largest, with REMAINDER and RELATIVE at the end.
 480:       // These are useful when determining sizes and weights.
 481:       ArrayList sortedByWidth = new ArrayList(components.length);
 482:       ArrayList sortedByHeight = new ArrayList(components.length);
 483: 
 484:       // STEP 1: first we figure out how many rows/columns
 485:       for (int i = 0; i < components.length; i++)
 486:     {
 487:           Component component = components [i];
 488:         
 489:           // If component is not visible we dont have to care about it.
 490:           if (!component.isVisible())
 491:             continue;
 492:         
 493:           // When looking up the constraint for the first time, check the
 494:           // original unmodified constraint.  After the first time, always
 495:           // refer to the internal modified constraint.
 496:           GridBagConstraints originalConstraints = lookupConstraints (component);
 497:           GridBagConstraints constraints = (GridBagConstraints) originalConstraints.clone();
 498:           internalcomptable.put(component, constraints);
 499: 
 500:           // Cases:
 501:           //
 502:           // 1. gridy == RELATIVE, gridx == RELATIVE
 503:           //
 504:           //       use y as the row number; check for the next
 505:           //       available slot at row y
 506:           //
 507:           // 2. only gridx == RELATIVE
 508:           //
 509:           //       check for the next available slot at row gridy
 510:           //
 511:           // 3. only gridy == RELATIVE
 512:           //
 513:           //       check for the next available slot at column gridx
 514:           //
 515:           // 4. neither gridx or gridy == RELATIVE
 516:           //
 517:           //       nothing to check; just add it
 518: 
 519: 
 520:           // cases 1 and 2
 521:           if(constraints.gridx == GridBagConstraints.RELATIVE)
 522:             {
 523:               if (constraints.gridy == GridBagConstraints.RELATIVE)
 524:               constraints.gridy = current_y;
 525: 
 526:               int x;
 527: 
 528:               // Check the component that occupies the right-most spot in this
 529:               // row. We want to add this component after it.
 530:               // If this row is empty, add to the 0 position.
 531:               if (!lastInRow.containsKey(new Integer(constraints.gridy))) 
 532:                 x = 0;
 533:               else
 534:                 {
 535:                   Component lastComponent = (Component) lastInRow.get(new Integer(constraints.gridy));
 536:                   GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent);
 537:                   x = lastConstraints.gridx + Math.max(1, lastConstraints.gridwidth);
 538:                 }
 539: 
 540:               // Determine if this component will fit in the slot vertically.
 541:               // If not, bump it over to where it does fit.
 542:               for (int y = constraints.gridy + 1; y < constraints.gridy + Math.max(1, constraints.gridheight); y++)
 543:                 {
 544:                   if (lastInRow.containsKey(new Integer(y)))
 545:                     {
 546:                       Component lastComponent = (Component) lastInRow.get(new Integer(y));
 547:                       GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent);
 548:                       x = Math.max (x,
 549:                                     lastConstraints.gridx + Math.max(1, lastConstraints.gridwidth));
 550:                     }
 551:                 }
 552: 
 553:               constraints.gridx = x;
 554:             }
 555:           // case 3
 556:           else if(constraints.gridy == GridBagConstraints.RELATIVE)
 557:             {
 558:               int y;
 559:               // Check the component that occupies the bottom-most spot in
 560:               // this column. We want to add this component below it.
 561:               // If this column is empty, add to the 0 position.
 562:               if (!lastInCol.containsKey(new Integer(constraints.gridx))) 
 563:                 y = 0;
 564:               else
 565:                 {
 566:                   Component lastComponent = (Component)lastInCol.get(new Integer(constraints.gridx));
 567:                   GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent);
 568:                   y = lastConstraints.gridy + Math.max(1, lastConstraints.gridheight);
 569:                 }
 570: 
 571:               // Determine if this component will fit in the slot horizontally.
 572:               // If not, bump it down to where it does fit.
 573:               for (int x = constraints.gridx + 1; x < constraints.gridx + Math.max(1, constraints.gridwidth); x++)
 574:                 {
 575:                   if (lastInCol.containsKey(new Integer(x)))
 576:                     {
 577:                       Component lastComponent = (Component) lastInCol.get(new Integer(x));
 578:                       GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent);
 579:                       y = Math.max (y,
 580:                                     lastConstraints.gridy + Math.max(1, lastConstraints.gridheight));
 581:                     }
 582:                 }
 583: 
 584:               constraints.gridy = y;
 585:             }
 586:           // case 4: do nothing
 587: 
 588:           max_x = Math.max(max_x, 
 589:                            constraints.gridx + Math.max(1, constraints.gridwidth));
 590:           max_y = Math.max(max_y,
 591:                            constraints.gridy + Math.max(1, constraints.gridheight));
 592: 
 593:           sortBySpan(component, constraints.gridwidth, sortedByWidth, true);
 594:           sortBySpan(component, constraints.gridheight, sortedByHeight, false);
 595: 
 596:           // Update our reference points for RELATIVE gridx and gridy.
 597:           if(constraints.gridwidth == GridBagConstraints.REMAINDER)
 598:         {
 599:               current_y = constraints.gridy + Math.max(1, constraints.gridheight);
 600:         }
 601:           else if (constraints.gridwidth != GridBagConstraints.REMAINDER)
 602:         {
 603:               for (int y = constraints.gridy; y < constraints.gridy + Math.max(1, constraints.gridheight); y++)
 604:                 {
 605:                   if(lastInRow.containsKey(new Integer(y)))
 606:                     {
 607:                       Component lastComponent = (Component) lastInRow.get(new Integer(y));
 608:                       GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent);
 609:                       if (constraints.gridx > lastConstraints.gridx)
 610:                         {
 611:                           lastInRow.put(new Integer(y), component);
 612:                         }
 613:                     }
 614:                   else
 615:                     {
 616:                       lastInRow.put(new Integer(y), component);
 617:                     }
 618:                 }
 619: 
 620:               for (int x = constraints.gridx; x < constraints.gridx + Math.max(1, constraints.gridwidth); x++)
 621:                 {
 622:                   if(lastInCol.containsKey(new Integer(x)))
 623:                     {
 624:                       Component lastComponent = (Component) lastInCol.get(new Integer(x));
 625:                       GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent);
 626:                       if (constraints.gridy > lastConstraints.gridy)
 627:                         {
 628:                           lastInCol.put(new Integer(x), component);
 629:                         }
 630:                     }
 631:                   else
 632:                     {
 633:                       lastInCol.put(new Integer(x), component);
 634:                     }
 635:                 }
 636:         }
 637:     } // end of STEP 1
 638:     
 639:       GridBagLayoutInfo info = new GridBagLayoutInfo(max_x, max_y);
 640: 
 641:       // Check if column widths and row heights are overridden.
 642: 
 643:       for (int x = 0; x < max_x; x++)
 644:         {
 645:           if(columnWidths != null && columnWidths.length > x)
 646:             info.colWidths[x] = columnWidths[x];
 647:           if(columnWeights != null && columnWeights.length > x)
 648:             info.colWeights[x] = columnWeights[x];
 649:         }
 650: 
 651:       for (int y = 0; y < max_y; y++)
 652:         {
 653:           if(rowHeights != null && rowHeights.length > y)
 654:             info.rowHeights[y] = rowHeights[y];
 655:           if(rowWeights != null && rowWeights.length > y)
 656:             info.rowWeights[y] = rowWeights[y];
 657:         }
 658: 
 659:       // STEP 2: Fix up any cells with width/height as REMAINDER/RELATIVE.
 660:       for (int i = 0; i < components.length; i++)
 661:         {
 662:           Component component = components [i];
 663:             
 664:           // If component is not visible we dont have to care about it.
 665:           if (!component.isVisible())
 666:             continue;
 667:             
 668:           GridBagConstraints constraints = lookupInternalConstraints (component);
 669: 
 670:           if(constraints.gridwidth == GridBagConstraints.REMAINDER || constraints.gridwidth == GridBagConstraints.RELATIVE)
 671:             {
 672:               if(constraints.gridwidth == GridBagConstraints.REMAINDER)
 673:                 {
 674:                   for (int y = constraints.gridy; y < constraints.gridy + Math.max(1, constraints.gridheight); y++)
 675:                     {
 676:                       if (lastInRow.containsKey(new Integer(y)))
 677:                         {
 678:                           Component lastComponent = (Component) lastInRow.get(new Integer(y));
 679:                           GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent);
 680: 
 681:                           if (lastConstraints.gridwidth == GridBagConstraints.RELATIVE)
 682:                             {
 683:                               constraints.gridx = max_x - 1;
 684:                               break;
 685:                             }
 686:                           else
 687:                             {
 688:                               constraints.gridx = Math.max (constraints.gridx,
 689:                                                             lastConstraints.gridx + Math.max (1, lastConstraints.gridwidth));
 690:                             }
 691:                         }
 692:                     }
 693:                   constraints.gridwidth = max_x - constraints.gridx;
 694:                 }
 695:               else if (constraints.gridwidth == GridBagConstraints.RELATIVE)
 696:                 {
 697:                   constraints.gridwidth = max_x - constraints.gridx - 1;
 698:                 }
 699: 
 700:               // Re-sort
 701:               sortedByWidth.remove(sortedByWidth.indexOf(component));
 702:               sortBySpan(component, constraints.gridwidth, sortedByWidth, true);
 703:             }
 704: 
 705:           if(constraints.gridheight == GridBagConstraints.REMAINDER || constraints.gridheight == GridBagConstraints.RELATIVE)
 706:             {
 707:               if(constraints.gridheight == GridBagConstraints.REMAINDER)
 708:                 {
 709:                   for (int x = constraints.gridx; x < constraints.gridx + Math.max(1, constraints.gridwidth); x++)
 710:                     {
 711:                       if (lastInCol.containsKey(new Integer(x)))
 712:                         {
 713:                           Component lastComponent = (Component) lastInRow.get(new Integer(x));
 714:                           if (lastComponent != null)
 715:                             {
 716:                               GridBagConstraints lastConstraints = lookupInternalConstraints(lastComponent);
 717:     
 718:                               if (lastConstraints.gridheight == GridBagConstraints.RELATIVE)
 719:                                 {
 720:                                   constraints.gridy = max_y - 1;
 721:                                   break;
 722:                                 }
 723:                               else
 724:                                 {
 725:                                   constraints.gridy = Math.max (constraints.gridy,
 726:                                                                 lastConstraints.gridy + Math.max (1, lastConstraints.gridheight));
 727:                                 }
 728:                             }
 729:                         }
 730:                     }
 731:                   constraints.gridheight = max_y - constraints.gridy;
 732:                 }
 733:               else if (constraints.gridheight == GridBagConstraints.RELATIVE)
 734:                 {
 735:                   constraints.gridheight = max_y - constraints.gridy - 1;
 736:                 }
 737: 
 738:               // Re-sort
 739:               sortedByHeight.remove(sortedByHeight.indexOf(component));
 740:               sortBySpan(component, constraints.gridheight, sortedByHeight, false);
 741:             }
 742:         } // end of STEP 2
 743: 
 744:       // STEP 3: Determine sizes and weights for columns.
 745:       for (int i = 0; i < sortedByWidth.size(); i++)
 746:         {
 747:           Component component = (Component) sortedByWidth.get(i);
 748:             
 749:           // If component is not visible we dont have to care about it.
 750:           if (!component.isVisible())
 751:             continue;
 752: 
 753:           GridBagConstraints constraints = lookupInternalConstraints (component);
 754: 
 755:           int width = (sizeflag == PREFERREDSIZE) ?
 756:                       component.getPreferredSize().width :
 757:                       component.getMinimumSize().width;
 758: 
 759:           if(constraints.insets != null)
 760:             width += constraints.insets.left + constraints.insets.right;
 761: 
 762:           width += constraints.ipadx;
 763: 
 764:           distributeSizeAndWeight(width,
 765:                                   constraints.weightx, 
 766:                                   constraints.gridx,
 767:                                   constraints.gridwidth,
 768:                                   info.colWidths,
 769:                                   info.colWeights);
 770:         } // end of STEP 3
 771: 
 772:       // STEP 4: Determine sizes and weights for rows.
 773:       for (int i = 0; i < sortedByHeight.size(); i++)
 774:         {
 775:           Component component = (Component) sortedByHeight.get(i);
 776:             
 777:           // If component is not visible we dont have to care about it.
 778:           if (!component.isVisible())
 779:             continue;
 780: 
 781:           GridBagConstraints constraints = lookupInternalConstraints (component);
 782: 
 783:           int height = (sizeflag == PREFERREDSIZE) ?
 784:                        component.getPreferredSize().height :
 785:                        component.getMinimumSize().height;
 786: 
 787:           if(constraints.insets != null)
 788:             height += constraints.insets.top + constraints.insets.bottom;
 789: 
 790:           height += constraints.ipady;
 791: 
 792:           distributeSizeAndWeight(height,
 793:                                   constraints.weighty, 
 794:                                   constraints.gridy,
 795:                                   constraints.gridheight,
 796:                                   info.rowHeights,
 797:                                   info.rowWeights);
 798:         } // end of STEP 4
 799: 
 800:       // Adjust cell sizes iff parent size not zero.
 801:       if (parentDim.width > 0 && parentDim.height > 0)
 802:         {
 803:           calcCellSizes (info.colWidths, info.colWeights, parentDim.width);
 804:           calcCellSizes (info.rowHeights, info.rowWeights, parentDim.height);
 805:         }
 806: 
 807:       int totalWidth = sumIntArray(info.colWidths);
 808:       int totalHeight = sumIntArray(info.rowHeights);
 809: 
 810:       // Make sure pos_x and pos_y are never negative.
 811:       if (totalWidth >= parentDim.width)
 812:         info.pos_x = parentInsets.left;
 813:       else
 814:         info.pos_x = parentInsets.left + (parentDim.width - totalWidth) / 2;
 815: 
 816:       if (totalHeight >= parentDim.height)
 817:         info.pos_y = parentInsets.top;
 818:       else
 819:         info.pos_y = parentInsets.top + (parentDim.height - totalHeight) / 2;
 820: 
 821:       // DEBUG
 822:       //dumpLayoutInfo (info);
 823: 
 824:       return info;
 825:     }
 826: 
 827:     /**
 828:      * Obsolete.
 829:      */
 830:     protected Dimension GetMinSize (Container parent, GridBagLayoutInfo info)
 831:     {
 832:       if (parent == null || info == null)
 833:         return new Dimension (0, 0);
 834: 
 835:       Insets insets = parent.getInsets();
 836:       int width = sumIntArray (info.colWidths) + insets.left + insets.right;
 837:       int height = sumIntArray (info.rowHeights) + insets.top + insets.bottom;
 838:       return new Dimension (width, height);
 839:     }
 840: 
 841:     /**
 842:      * @since 1.4
 843:      */
 844:     protected Dimension getMinSize (Container parent, GridBagLayoutInfo info)
 845:     {
 846:       return GetMinSize (parent, info);
 847:     }
 848: 
 849:     /**
 850:      * Helper method used by GetLayoutInfo to keep components sorted, either
 851:      * by gridwidth or gridheight.
 852:      *
 853:      * @param component   Component to add to the sorted list.
 854:      * @param span        Either the component's gridwidth or gridheight.
 855:      * @param list        <code>ArrayList</code> of components, sorted by
 856:      *                    their span.
 857:      * @param sortByWidth Flag indicating sorting index. If true, sort by
 858:      *                    width. Otherwise, sort by height.
 859:      * FIXME: Use a better sorting algorithm.
 860:      */
 861:     private void sortBySpan (Component component, int span, ArrayList list, boolean sortByWidth)
 862:     {
 863:       if (span == GridBagConstraints.REMAINDER
 864:           || span == GridBagConstraints.RELATIVE)
 865:         {
 866:           // Put all RELATIVE and REMAINDER components at the end.
 867:           list.add(component);
 868:         }
 869:       else
 870:         {
 871:           int i = 0;
 872:           if (list.size() > 0)
 873:             {
 874:               GridBagConstraints gbc = lookupInternalConstraints((Component) list.get(i));
 875:               int otherspan = sortByWidth ?
 876:                               gbc.gridwidth :
 877:                               gbc.gridheight;
 878:               while (otherspan != GridBagConstraints.REMAINDER
 879:                      && otherspan != GridBagConstraints.RELATIVE
 880:                      && span >= otherspan)
 881:                 {
 882:                   i++;
 883:                   if (i < list.size())
 884:                     {
 885:                       gbc = lookupInternalConstraints((Component) list.get(i));
 886:                       otherspan = sortByWidth ?
 887:                                   gbc.gridwidth :
 888:                                   gbc.gridheight;
 889:                     }
 890:                   else
 891:                     break;
 892:                 }
 893:             }
 894:           list.add(i, component);
 895:         }
 896:     }
 897: 
 898:     /**
 899:      * Helper method used by GetLayoutInfo to distribute a component's size
 900:      * and weight.
 901:      *
 902:      * @param size    Preferred size of component, with inset and padding
 903:      *                already added.
 904:      * @param weight  Weight of component.
 905:      * @param start   Starting position of component. Either
 906:      *                constraints.gridx or gridy.
 907:      * @param span    Span of component. either contraints.gridwidth or
 908:      *                gridheight.
 909:      * @param sizes   Sizes of rows or columns.
 910:      * @param weights Weights of rows or columns.
 911:      */
 912:     private void distributeSizeAndWeight (int size, double weight,
 913:                                           int start, int span,
 914:                                           int[] sizes, double[] weights)
 915:     {
 916:       if (span == 1)
 917:         {
 918:           sizes[start] = Math.max(sizes[start], size);
 919:           weights[start] = Math.max(weights[start], weight);
 920:         }
 921:       else if (span > 1)
 922:         {
 923:           int numOccupied = span;
 924:           int lastOccupied = -1;
 925: 
 926:           for(int i = start; i < start + span; i++)
 927:             {
 928:               if (sizes[i] == 0.0)
 929:                 numOccupied--;
 930:               else
 931:                 {
 932:                   size -= sizes[i];
 933:                   lastOccupied = i;
 934:                 }
 935:             }
 936: 
 937:           // A component needs to occupy at least one row.
 938:           if(numOccupied == 0)
 939:             sizes[start + span - 1] = size;
 940:           else if (size > 0)
 941:             sizes[lastOccupied] += size;
 942: 
 943:           calcCellWeights(weight, weights, start, span);
 944:         }
 945:     }
 946: 
 947:     /**
 948:      * Helper method used by GetLayoutInfo to calculate weight distribution.
 949:      * @param weight  Weight of component.
 950:      * @param weights Weights of rows/columns.
 951:      * @param start   Starting position of component in grid (gridx/gridy).
 952:      * @param span    Span of component (gridwidth/gridheight).
 953:      */
 954:     private void calcCellWeights (double weight, double[] weights, int start, int span)
 955:     {
 956:       double totalWeight = 0.0;
 957:       for(int k = start; k < start + span; k++)
 958:         totalWeight += weights[k];
 959: 
 960:       if(weight > totalWeight)
 961:         {
 962:           if (totalWeight == 0.0)
 963:             {
 964:               weights[start + span - 1] += weight;
 965:             }
 966:           else
 967:             {
 968:               double diff = weight - totalWeight ;
 969:               double remaining = diff;
 970: 
 971:               for(int k = start; k < start + span; k++)
 972:                 {
 973:                   double extraWeight = diff * weights[k] / totalWeight;
 974:                   weights[k] += extraWeight;
 975:                   remaining -= extraWeight;
 976:                 } 
 977: 
 978:               if (remaining > 0.0 && weights[start + span - 1] != 0.0)
 979:                 {
 980:                   weights[start + span - 1] += remaining;
 981:                 }
 982:             }
 983:         }
 984:     }
 985: 
 986:     /**
 987:      * Helper method used by GetLayoutInfo to distribute extra space
 988:      * based on weight distribution.
 989:      *
 990:      * @param sizes   Sizes of rows/columns.
 991:      * @param weights Weights of rows/columns.
 992:      * @param range   Dimension of container.
 993:      */
 994:     private void calcCellSizes (int[] sizes, double[] weights, int range)
 995:     {
 996:       int totalSize = sumIntArray (sizes);
 997:       double totalWeight = sumDoubleArray (weights);
 998: 
 999:       int diff = range - totalSize;
1000: 
1001:       if (diff == 0)
1002:         return;
1003: 
1004:       for (int i = 0; i < sizes.length; i++)
1005:         {
1006:           int newsize = (int) (sizes[i] + (((double) diff) * weights [i] / totalWeight ));
1007: 
1008:           if (newsize > 0)
1009:             sizes[i] = newsize;
1010:         }
1011:     }
1012: 
1013:     private void dumpLayoutInfo (GridBagLayoutInfo info)
1014:     {
1015:     System.out.println ("GridBagLayoutInfo:");
1016:     System.out.println ("cols: " + info.cols + ", rows: " + info.rows);
1017:     System.out.print ("colWidths: ");
1018:     dumpArray(info.colWidths);
1019:     System.out.print ("rowHeights: ");
1020:     dumpArray(info.rowHeights);
1021:     System.out.print ("colWeights: ");
1022:     dumpArray(info.colWeights);
1023:     System.out.print ("rowWeights: ");
1024:     dumpArray(info.rowWeights);
1025:     }
1026: 
1027:     private void dumpArray(int[] array)
1028:     {
1029:     String sep = "";
1030:     for(int i = 0; i < array.length; i++)
1031:     {
1032:         System.out.print(sep);
1033:         System.out.print(array[i]);
1034:         sep = ", ";
1035:     }
1036:     System.out.println();
1037:     }
1038: 
1039:     private void dumpArray(double[] array)
1040:     {
1041:     String sep = "";
1042:     for(int i = 0; i < array.length; i++)
1043:     {
1044:         System.out.print(sep);
1045:         System.out.print(array[i]);
1046:         sep = ", ";
1047:     }
1048:     System.out.println();
1049:     }
1050:   
1051:     /**
1052:      * @since 1.4
1053:      */
1054:     protected void arrangeGrid (Container parent)
1055:     {
1056:       ArrangeGrid (parent);
1057:     }
1058: 
1059:     /**
1060:      * @since 1.4
1061:      */
1062:     protected GridBagLayoutInfo getLayoutInfo (Container parent, int sizeflag)
1063:     {
1064:       return GetLayoutInfo (parent, sizeflag);
1065:     }
1066: 
1067:     /**
1068:      * @since 1.4
1069:      */
1070:     protected void adjustForGravity (GridBagConstraints gbc, Rectangle rect)
1071:     {
1072:       AdjustForGravity (gbc, rect);
1073:     }
1074: }