Source for java.awt.GridBagLayout

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