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