001 /* GridBagLayout - Layout manager for components according to GridBagConstraints 002 Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. 003 004 This file is part of GNU Classpath. 005 006 GNU Classpath is free software; you can redistribute it and/or modify 007 it under the terms of the GNU General Public License as published by 008 the Free Software Foundation; either version 2, or (at your option) 009 any later version. 010 011 GNU Classpath is distributed in the hope that it will be useful, but 012 WITHOUT ANY WARRANTY; without even the implied warranty of 013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 General Public License for more details. 015 016 You should have received a copy of the GNU General Public License 017 along with GNU Classpath; see the file COPYING. If not, write to the 018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 019 02110-1301 USA. 020 021 Linking this library statically or dynamically with other modules is 022 making a combined work based on this library. Thus, the terms and 023 conditions of the GNU General Public License cover the whole 024 combination. 025 026 As a special exception, the copyright holders of this library give you 027 permission to link this library with independent modules to produce an 028 executable, regardless of the license terms of these independent 029 modules, and to copy and distribute the resulting executable under 030 terms of your choice, provided that you also meet, for each linked 031 independent module, the terms and conditions of the license of that 032 module. An independent module is a module which is not derived from 033 or based on this library. If you modify this library, you may extend 034 this exception to your version of the library, but you are not 035 obligated to do so. If you do not wish to do so, delete this 036 exception statement from your version. */ 037 038 039 package java.awt; 040 041 import java.io.Serializable; 042 import java.util.ArrayList; 043 import java.util.HashMap; 044 import java.util.Hashtable; 045 046 /** 047 * @author Michael Koch (konqueror@gmx.de) 048 * @author Jeroen Frijters (jeroen@frijters.net) 049 * @author Andrew John Hughes (gnu_andrew@member.fsf.org) 050 */ 051 public class GridBagLayout 052 implements Serializable, LayoutManager2 053 { 054 private static final long serialVersionUID = 8838754796412211005L; 055 056 protected static final int MINSIZE = 1; 057 protected static final int PREFERREDSIZE = 2; 058 protected static final int MAXGRIDSIZE = 512; 059 060 // comptable remembers the original contraints given to us. 061 // internalcomptable is used to keep track of modified constraint values 062 // that we calculate, particularly when we are given RELATIVE and 063 // REMAINDER constraints. 064 // Constraints kept in comptable are never modified, and constraints 065 // kept in internalcomptable can be modified internally only. 066 protected Hashtable<Component,GridBagConstraints> comptable; 067 private Hashtable<Component,GridBagConstraints> internalcomptable; 068 protected GridBagLayoutInfo layoutInfo; 069 protected GridBagConstraints defaultConstraints; 070 071 public double[] columnWeights; 072 public int[] columnWidths; 073 public double[] rowWeights; 074 public int[] rowHeights; 075 076 public GridBagLayout () 077 { 078 this.comptable = new Hashtable<Component,GridBagConstraints>(); 079 this.internalcomptable = new Hashtable<Component,GridBagConstraints>(); 080 this.defaultConstraints= new GridBagConstraints(); 081 } 082 083 /** 084 * Helper method to calc the sum of a range of elements in an int array. 085 */ 086 private int sumIntArray (int[] array, int upto) 087 { 088 int result = 0; 089 090 for (int i = 0; i < upto; i++) 091 result += array [i]; 092 093 return result; 094 } 095 096 /** 097 * Helper method to calc the sum of all elements in an int array. 098 */ 099 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 }