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