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