1 30 31 package com.jgoodies.forms.layout; 32 33 import java.awt.Component ; 34 import java.awt.Container ; 35 import java.awt.Dimension ; 36 import java.awt.Insets ; 37 import java.awt.LayoutManager2 ; 38 import java.awt.Rectangle ; 39 import java.util.*; 40 41 42 143 144 public final class FormLayout implements LayoutManager2 { 145 146 150 private final List colSpecs; 151 152 156 private final List rowSpecs; 157 158 162 private int[][] colGroupIndices; 163 164 168 private int[][] rowGroupIndices; 169 170 174 private final Map constraintMap; 175 176 177 179 183 private List[] colComponents; 184 185 189 private List[] rowComponents; 190 191 195 private final ComponentSizeCache componentSizeCache; 196 197 203 private final Measure minimumWidthMeasure; 204 private final Measure minimumHeightMeasure; 205 private final Measure preferredWidthMeasure; 206 private final Measure preferredHeightMeasure; 207 208 209 211 219 public FormLayout(ColumnSpec[] colSpecs, RowSpec[] rowSpecs) { 220 if (colSpecs == null) 221 throw new NullPointerException ("Column specifications must not be null."); 222 if (rowSpecs == null) 223 throw new NullPointerException ("Row specifications must not be null."); 224 225 this.colSpecs = new ArrayList(Arrays.asList(colSpecs)); 226 this.rowSpecs = new ArrayList(Arrays.asList(rowSpecs)); 227 colGroupIndices = new int[][]{}; 228 rowGroupIndices = new int[][]{}; 229 int initialCapacity = colSpecs.length * rowSpecs.length / 4; 230 constraintMap = new HashMap(initialCapacity); 231 componentSizeCache = new ComponentSizeCache(initialCapacity); 232 minimumWidthMeasure = new MinimumWidthMeasure(componentSizeCache); 233 minimumHeightMeasure = new MinimumHeightMeasure(componentSizeCache); 234 preferredWidthMeasure = new PreferredWidthMeasure(componentSizeCache); 235 preferredHeightMeasure = new PreferredHeightMeasure(componentSizeCache); 236 } 237 238 239 249 public FormLayout(String encodedColumnSpecs, String encodedRowSpecs) { 250 this(decodeColSpecs(encodedColumnSpecs), 251 decodeRowSpecs(encodedRowSpecs)); 252 } 253 254 255 269 public FormLayout(String encodedColumnSpecs) { 270 this(encodedColumnSpecs, ""); 271 } 272 273 274 276 281 public int getColumnCount() { 282 return colSpecs.size(); 283 } 284 285 290 public int getRowCount() { 291 return rowSpecs.size(); 292 } 293 294 301 public ColumnSpec getColumnSpec(int columnIndex) { 302 return (ColumnSpec) colSpecs.get(columnIndex - 1); 303 } 304 305 312 public RowSpec getRowSpec(int rowIndex) { 313 return (RowSpec) rowSpecs.get(rowIndex - 1); 314 } 315 316 322 public void appendColumn(ColumnSpec columnSpec) { 323 if (columnSpec == null) { 324 throw new NullPointerException ("The column spec must not be null."); 325 } 326 colSpecs.add(columnSpec); 327 } 328 329 346 public void insertColumn(int columnIndex, ColumnSpec columnSpec) { 347 if (columnIndex < 1 || columnIndex > getColumnCount()) { 348 throw new IndexOutOfBoundsException ( 349 "The column index " + columnIndex + 350 "must be in the range [1, " + getColumnCount() + "]."); 351 } 352 colSpecs.add(columnIndex - 1, columnSpec); 353 shiftComponentsHorizontally(columnIndex, false); 354 adjustGroupIndices(colGroupIndices, columnIndex, false); 355 } 356 357 358 377 public void removeColumn(int columnIndex) { 378 if (columnIndex < 1 || columnIndex > getColumnCount()) { 379 throw new IndexOutOfBoundsException ( 380 "The column index " + columnIndex + 381 " must be in the range [1, " + getColumnCount() + "]."); 382 } 383 colSpecs.remove(columnIndex - 1); 384 shiftComponentsHorizontally(columnIndex, true); 385 adjustGroupIndices(colGroupIndices, columnIndex, true); 386 } 387 388 394 public void appendRow(RowSpec rowSpec) { 395 if (rowSpec == null) { 396 throw new NullPointerException ("The row spec must not be null."); 397 } 398 rowSpecs.add(rowSpec); 399 } 400 401 418 public void insertRow(int rowIndex, RowSpec rowSpec) { 419 if (rowIndex < 1 || rowIndex > getRowCount()) { 420 throw new IndexOutOfBoundsException ( 421 "The row index " + rowIndex + 422 " must be in the range [1, " + getRowCount() + "]."); 423 } 424 rowSpecs.add(rowIndex - 1, rowSpec); 425 shiftComponentsVertically(rowIndex, false); 426 adjustGroupIndices(rowGroupIndices, rowIndex, false); 427 } 428 429 446 public void removeRow(int rowIndex) { 447 if (rowIndex < 1 || rowIndex > getRowCount()) { 448 throw new IndexOutOfBoundsException ( 449 "The row index " + rowIndex + 450 "must be in the range [1, " + getRowCount() + "]."); 451 } 452 rowSpecs.remove(rowIndex - 1); 453 shiftComponentsVertically(rowIndex, true); 454 adjustGroupIndices(rowGroupIndices, rowIndex, true); 455 } 456 457 458 466 private void shiftComponentsHorizontally(int columnIndex, boolean remove) { 467 final int offset = remove ? -1 : 1; 468 for (Iterator i = constraintMap.entrySet().iterator(); i.hasNext(); ) { 469 Map.Entry entry = (Map.Entry) i.next(); 470 CellConstraints constraints = (CellConstraints) entry.getValue(); 471 int x1 = constraints.gridX; 472 int w = constraints.gridWidth; 473 int x2 = x1 + w - 1; 474 if (x1 == columnIndex && remove) { 475 throw new IllegalStateException ( 476 "The removed column " + columnIndex + 477 " must not contain component origins.\n" + 478 "Illegal component=" + entry.getKey()); 479 } else if (x1 >= columnIndex) { 480 constraints.gridX += offset; 481 } else if (x2 >= columnIndex) { 482 constraints.gridWidth += offset; 483 } 484 } 485 } 486 487 495 private void shiftComponentsVertically(int rowIndex, boolean remove) { 496 final int offset = remove ? -1 : 1; 497 for (Iterator i = constraintMap.entrySet().iterator(); i.hasNext(); ) { 498 Map.Entry entry = (Map.Entry) i.next(); 499 CellConstraints constraints = (CellConstraints) entry.getValue(); 500 int y1 = constraints.gridY; 501 int h = constraints.gridHeight; 502 int y2 = y1 + h - 1; 503 if (y1 == rowIndex && remove) { 504 throw new IllegalStateException ( 505 "The removed row " + rowIndex + 506 " must not contain component origins.\n" + 507 "Illegal component=" + entry.getKey()); 508 } else if (y1 >= rowIndex) { 509 constraints.gridY += offset; 510 } else if (y2 >= rowIndex) { 511 constraints.gridHeight += offset; 512 } 513 } 514 } 515 516 525 private void adjustGroupIndices(int[][] allGroupIndices, 526 int modifiedIndex, boolean remove) { 527 final int offset = remove ? -1 : +1; 528 for (int group = 0; group < allGroupIndices.length; group++) { 529 int[] groupIndices = allGroupIndices[group]; 530 for (int i = 0; i < groupIndices.length; i++) { 531 int index = groupIndices[i]; 532 if (index == modifiedIndex && remove) { 533 throw new IllegalStateException ( 534 "The removed index " + modifiedIndex + " must not be grouped."); 535 } else if (index >= modifiedIndex) { 536 groupIndices[i] += offset; 537 } 538 } 539 } 540 } 541 542 543 545 553 public void setConstraints(Component component, CellConstraints constraints) { 554 if (component == null) 555 throw new NullPointerException ("Component must not be null."); 556 if (constraints == null) 557 throw new NullPointerException ("Constraint must not be null."); 558 559 constraints.ensureValidGridBounds(getColumnCount(), getRowCount()); 560 constraintMap.put(component, constraints.clone()); 561 } 562 563 572 public CellConstraints getConstraints(Component component) { 573 if (component == null) 574 throw new NullPointerException ("Component must not be null."); 575 576 CellConstraints constraints = (CellConstraints) constraintMap.get(component); 577 if (constraints == null) 578 throw new NullPointerException ("Component has not been added to the container."); 579 580 return (CellConstraints) constraints.clone(); 581 } 582 583 588 private void removeConstraints(Component component) { 589 constraintMap.remove(component); 590 componentSizeCache.removeEntry(component); 591 } 592 593 594 596 601 public int[][] getColumnGroups() { 602 return deepClone(colGroupIndices); 603 } 604 605 621 public void setColumnGroups(int[][] colGroupIndices) { 622 int maxColumn = getColumnCount(); 623 boolean[] usedIndices = new boolean[maxColumn + 1]; 624 for (int group = 0; group < colGroupIndices.length; group++) { 625 for (int j = 0; j < colGroupIndices[group].length; j++) { 626 int colIndex = colGroupIndices[group][j]; 627 if (colIndex < 1 || colIndex > maxColumn) { 628 throw new IndexOutOfBoundsException ( 629 "Invalid column group index " + colIndex + 630 " in group " + (group+1)); 631 } 632 if (usedIndices[colIndex]) { 633 throw new IllegalArgumentException ( 634 "Column index " + colIndex + " must not be used in multiple column groups."); 635 } else { 636 usedIndices[colIndex] = true; 637 } 638 } 639 } 640 this.colGroupIndices = deepClone(colGroupIndices); 641 } 642 643 649 public void addGroupedColumn(int columnIndex) { 650 int[][] newColGroups = getColumnGroups(); 651 if (newColGroups.length == 0) { 653 newColGroups = new int[][]{{columnIndex}}; 654 } else { 655 int lastGroupIndex = newColGroups.length-1; 656 int[] lastGroup = newColGroups[lastGroupIndex]; 657 int groupSize = lastGroup.length; 658 int[] newLastGroup = new int[groupSize+1]; 659 System.arraycopy(lastGroup, 0, newLastGroup, 0, groupSize); 660 newLastGroup[groupSize] = columnIndex; 661 newColGroups[lastGroupIndex] = newLastGroup; 662 } 663 setColumnGroups(newColGroups); 664 } 665 666 671 public int[][] getRowGroups() { 672 return deepClone(rowGroupIndices); 673 } 674 675 690 public void setRowGroups(int[][] rowGroupIndices) { 691 int rowCount = getRowCount(); 692 boolean[] usedIndices = new boolean[rowCount + 1]; 693 for (int i = 0; i < rowGroupIndices.length; i++) { 694 for (int j = 0; j < rowGroupIndices[i].length; j++) { 695 int rowIndex = rowGroupIndices[i][j]; 696 if (rowIndex < 1 || rowIndex > rowCount) { 697 throw new IndexOutOfBoundsException ( 698 "Invalid row group index " + rowIndex + 699 " in group " + (i+1)); 700 } 701 if (usedIndices[rowIndex]) { 702 throw new IllegalArgumentException ( 703 "Row index " + rowIndex + " must not be used in multiple row groups."); 704 } else { 705 usedIndices[rowIndex] = true; 706 } 707 } 708 } 709 this.rowGroupIndices = deepClone(rowGroupIndices); 710 } 711 712 718 public void addGroupedRow(int rowIndex) { 719 int[][] newRowGroups = getRowGroups(); 720 if (newRowGroups.length == 0) { 722 newRowGroups = new int[][]{{rowIndex}}; 723 } else { 724 int lastGroupIndex = newRowGroups.length-1; 725 int[] lastGroup = newRowGroups[lastGroupIndex]; 726 int groupSize = lastGroup.length; 727 int[] newLastGroup = new int[groupSize+1]; 728 System.arraycopy(lastGroup, 0, newLastGroup, 0, groupSize); 729 newLastGroup[groupSize] = rowIndex; 730 newRowGroups[lastGroupIndex] = newLastGroup; 731 } 732 setRowGroups(newRowGroups); 733 } 734 735 736 738 746 public void addLayoutComponent(String name, Component component) { 747 throw new UnsupportedOperationException ( 748 "Use #addLayoutComponent(Component, Object) instead."); 749 } 750 751 763 public void addLayoutComponent(Component comp, Object constraints) { 764 if (constraints instanceof String ) { 765 setConstraints(comp, new CellConstraints((String ) constraints)); 766 } else if (constraints instanceof CellConstraints) { 767 setConstraints(comp, (CellConstraints) constraints); 768 } else if (constraints == null) { 769 throw new NullPointerException ("Constraints must not be null."); 770 } else { 771 throw new IllegalArgumentException ("Illegal constraint type " + constraints.getClass()); 772 } 773 } 774 775 784 public void removeLayoutComponent(Component comp) { 785 removeConstraints(comp); 786 } 787 788 789 791 800 public Dimension minimumLayoutSize(Container parent) { 801 return computeLayoutSize(parent, 802 minimumWidthMeasure, 803 minimumHeightMeasure); 804 } 805 806 816 public Dimension preferredLayoutSize(Container parent) { 817 return computeLayoutSize(parent, 818 preferredWidthMeasure, 819 preferredHeightMeasure); 820 } 821 822 832 public Dimension maximumLayoutSize(Container target) { 833 return new Dimension (Integer.MAX_VALUE, Integer.MAX_VALUE); 834 } 835 836 845 public float getLayoutAlignmentX(Container parent) { 846 return 0.5f; 847 } 848 849 858 public float getLayoutAlignmentY(Container parent) { 859 return 0.5f; 860 } 861 862 863 867 public void invalidateLayout(Container target) { 868 invalidateCaches(); 869 } 870 871 872 894 public void layoutContainer(Container parent) { 895 synchronized (parent.getTreeLock()) { 896 initializeColAndRowComponentLists(); 897 Dimension size = parent.getSize(); 898 899 Insets insets = parent.getInsets(); 900 int totalWidth = size.width - insets.left - insets.right; 901 int totalHeight = size.height- insets.top - insets.bottom; 902 903 int[] x = computeGridOrigins(parent, 904 totalWidth, insets.left, 905 colSpecs, 906 colComponents, 907 colGroupIndices, 908 minimumWidthMeasure, 909 preferredWidthMeasure 910 ); 911 int[] y = computeGridOrigins(parent, 912 totalHeight, insets.top, 913 rowSpecs, 914 rowComponents, 915 rowGroupIndices, 916 minimumHeightMeasure, 917 preferredHeightMeasure 918 ); 919 920 layoutComponents(x, y); 921 } 922 } 923 924 926 934 private void initializeColAndRowComponentLists() { 935 colComponents = new LinkedList[getColumnCount()]; 936 for (int i=0; i < getColumnCount(); i++) { 937 colComponents[i] = new LinkedList(); 938 } 939 940 rowComponents = new LinkedList[getRowCount()]; 941 for (int i=0; i < getRowCount(); i++) { 942 rowComponents[i] = new LinkedList(); 943 } 944 945 for (Iterator i = constraintMap.entrySet().iterator(); i.hasNext(); ) { 946 Map.Entry entry = (Map.Entry) i.next(); 947 Component component = (Component ) entry.getKey(); 948 if (!component.isVisible()) 949 continue; 950 951 CellConstraints constraints = (CellConstraints) entry.getValue(); 952 if (constraints.gridWidth == 1) 953 colComponents[constraints.gridX-1].add(component); 954 955 if (constraints.gridHeight == 1) 956 rowComponents[constraints.gridY-1].add(component); 957 } 958 } 959 960 961 968 private Dimension computeLayoutSize(Container parent, 969 Measure defaultWidthMeasure, 970 Measure defaultHeightMeasure) { 971 synchronized (parent.getTreeLock()) { 972 initializeColAndRowComponentLists(); 973 int[] colWidths = maximumSizes(parent, colSpecs, colComponents, 974 minimumWidthMeasure, 975 preferredWidthMeasure, 976 defaultWidthMeasure); 977 int[] rowHeights = maximumSizes(parent, rowSpecs, rowComponents, 978 minimumHeightMeasure, 979 preferredHeightMeasure, 980 defaultHeightMeasure); 981 int[] groupedWidths = groupedSizes(colGroupIndices, colWidths); 982 int[] groupedHeights = groupedSizes(rowGroupIndices, rowHeights); 983 984 int[] xOrigins = computeOrigins(groupedWidths, 0); 986 int[] yOrigins = computeOrigins(groupedHeights, 0); 987 988 int width1 = sum(groupedWidths); 989 int height1 = sum(groupedHeights); 990 int maxWidth = width1; 991 int maxHeight = height1; 992 993 1000 boolean canGrowHorizontally = containsSpecThatCanGrow(colSpecs); 1002 boolean canGrowVertically = containsSpecThatCanGrow(rowSpecs); 1003 1004 for (Iterator i = constraintMap.entrySet().iterator(); i.hasNext(); ) { 1005 Map.Entry entry = (Map.Entry) i.next(); 1006 Component component = (Component ) entry.getKey(); 1007 if (!component.isVisible()) 1008 continue; 1009 1010 CellConstraints constraints = (CellConstraints) entry.getValue(); 1011 if (canGrowHorizontally && (constraints.gridWidth > 1)) { 1012 int compWidth = defaultWidthMeasure.sizeOf(component); 1014 int gridX1 = constraints.gridX-1; 1016 int gridX2 = gridX1 + constraints.gridWidth; 1017 int lead = xOrigins[gridX1]; 1018 int trail = width1 - xOrigins[gridX2]; 1019 int myWidth = lead + compWidth + trail; 1020 if (myWidth > maxWidth) { 1021 maxWidth = myWidth; 1022 } 1023 } 1024 1025 if (canGrowVertically && (constraints.gridHeight > 1)) { 1026 int compHeight = defaultHeightMeasure.sizeOf(component); 1028 int gridY1 = constraints.gridY-1; 1030 int gridY2 = gridY1 + constraints.gridHeight; 1031 int lead = yOrigins[gridY1]; 1032 int trail = height1 - yOrigins[gridY2]; 1033 int myHeight = lead + compHeight + trail; 1034 if (myHeight > maxHeight) { 1035 maxHeight = myHeight; 1036 } 1037 } 1038 } 1039 Insets insets = parent.getInsets(); 1040 int width = maxWidth + insets.left + insets.right; 1041 int height = maxHeight + insets.top + insets.bottom; 1042 return new Dimension (width, height); 1043 } 1044 } 1045 1046 1059 private int[] computeGridOrigins(Container container, 1060 int totalSize, int offset, 1061 List formSpecs, 1062 List[] componentLists, 1063 int[][] groupIndices, 1064 Measure minMeasure, 1065 Measure prefMeasure) { 1066 1069 int[] minSizes = maximumSizes(container, formSpecs, componentLists, 1070 minMeasure, prefMeasure, minMeasure); 1071 int[] prefSizes = maximumSizes(container, formSpecs, componentLists, 1072 minMeasure, prefMeasure, prefMeasure); 1073 1074 int[] groupedMinSizes = groupedSizes(groupIndices, minSizes); 1075 int[] groupedPrefSizes = groupedSizes(groupIndices, prefSizes); 1076 int totalMinSize = sum(groupedMinSizes); 1077 int totalPrefSize = sum(groupedPrefSizes); 1078 int[] compressedSizes = compressedSizes(formSpecs, 1079 totalSize, 1080 totalMinSize, 1081 totalPrefSize, 1082 groupedMinSizes, 1083 prefSizes); 1084 int[] groupedSizes = groupedSizes(groupIndices, compressedSizes); 1085 int totalGroupedSize = sum(groupedSizes); 1086 int[] sizes = distributedSizes(formSpecs, 1087 totalSize, 1088 totalGroupedSize, 1089 groupedSizes); 1090 return computeOrigins(sizes, offset); 1091 } 1092 1093 1094 1101 private int[] computeOrigins(int[] sizes, int offset) { 1102 int count = sizes.length; 1103 int origins[] = new int[count + 1]; 1104 origins[0] = offset; 1105 for (int i=1; i <= count; i++) { 1106 origins[i] = origins[i-1] + sizes[i-1]; 1107 } 1108 return origins; 1109 } 1110 1111 1126 private void layoutComponents(int[] x, int[] y) { 1127 Rectangle cellBounds = new Rectangle (); 1128 for (Iterator i = constraintMap.entrySet().iterator(); i.hasNext(); ) { 1129 Map.Entry entry = (Map.Entry) i.next(); 1130 Component component = (Component ) entry.getKey(); 1131 CellConstraints constraints = (CellConstraints) entry.getValue(); 1132 1133 int gridX = constraints.gridX-1; 1134 int gridY = constraints.gridY-1; 1135 int gridWidth = constraints.gridWidth; 1136 int gridHeight = constraints.gridHeight; 1137 cellBounds.x = x[gridX]; 1138 cellBounds.y = y[gridY]; 1139 cellBounds.width = x[gridX + gridWidth ] - cellBounds.x; 1140 cellBounds.height = y[gridY + gridHeight] - cellBounds.y; 1141 1142 constraints.setBounds(component, this, cellBounds, 1143 minimumWidthMeasure, minimumHeightMeasure, 1144 preferredWidthMeasure, preferredHeightMeasure); 1145 } 1146 } 1147 1148 1149 1152 private void invalidateCaches() { 1153 componentSizeCache.invalidate(); 1154 } 1155 1156 1157 1169 private int[] maximumSizes(Container container, 1170 List formSpecs, 1171 List[] componentLists, 1172 Measure minMeasure, 1173 Measure prefMeasure, 1174 Measure defaultMeasure) { 1175 FormSpec formSpec; 1176 int size = formSpecs.size(); 1177 int result[] = new int[size]; 1178 for (int i = 0; i < size; i++) { 1179 formSpec = (FormSpec) formSpecs.get(i); 1180 result[i] = formSpec.maximumSize(container, 1181 componentLists[i], 1182 minMeasure, 1183 prefMeasure, 1184 defaultMeasure); 1185 } 1186 return result; 1187 } 1188 1189 1190 1207 private int[] compressedSizes(List formSpecs, 1208 int totalSize, int totalMinSize, int totalPrefSize, 1209 int[] minSizes, int[] prefSizes) { 1210 1211 if (totalSize < totalMinSize) 1213 return minSizes; 1214 if (totalSize >= totalPrefSize) 1216 return prefSizes; 1217 1218 int count = formSpecs.size(); 1219 int[] sizes = new int[count]; 1220 1221 double totalCompressionSpace = totalPrefSize - totalSize; 1222 double maxCompressionSpace = totalPrefSize - totalMinSize; 1223 double compressionFactor = totalCompressionSpace / maxCompressionSpace; 1224 1225 1229 for (int i=0; i < count; i++) { 1230 FormSpec formSpec = (FormSpec) formSpecs.get(i); 1231 sizes[i] = prefSizes[i]; 1232 if (formSpec.getSize() == Sizes.DEFAULT) { 1233 sizes[i] -= (int) Math.round((prefSizes[i] - minSizes[i]) 1234 * compressionFactor); 1235 } 1236 } 1237 return sizes; 1238 } 1239 1240 1241 1249 private int[] groupedSizes(int[][] groups, int[] rawSizes) { 1250 if (groups == null || groups.length == 0) { 1252 return rawSizes; 1253 } 1254 1255 int[] sizes = new int[rawSizes.length]; 1257 for (int i = 0; i < sizes.length; i++) { 1258 sizes[i] = rawSizes[i]; 1259 } 1260 1261 for (int group = 0; group < groups.length; group++) { 1263 int[] groupIndices = groups[group]; 1264 int groupMaxSize = 0; 1265 for (int i = 0; i < groupIndices.length; i++) { 1267 int index = groupIndices[i] - 1; 1268 groupMaxSize = Math.max(groupMaxSize, sizes[index]); 1269 } 1270 for (int i = 0; i < groupIndices.length; i++) { 1272 int index = groupIndices[i] - 1; 1273 sizes[index] = groupMaxSize; 1274 } 1275 } 1276 return sizes; 1277 } 1278 1279 1280 1290 private int[] distributedSizes(List formSpecs, 1291 int totalSize, int totalPrefSize, 1292 int[] inputSizes) { 1293 double totalFreeSpace = totalSize - totalPrefSize; 1294 if (totalFreeSpace < 0) 1296 return inputSizes; 1297 1298 int count = formSpecs.size(); 1300 double totalWeight = 0.0; 1301 for (int i=0; i < count; i++) { 1302 FormSpec formSpec = (FormSpec) formSpecs.get(i); 1303 totalWeight += formSpec.getResizeWeight(); 1304 } 1305 1306 if (totalWeight == 0.0) 1308 return inputSizes; 1309 1310 int[] sizes = new int[count]; 1311 1312 double restSpace = totalFreeSpace; 1313 int roundedRestSpace = (int) totalFreeSpace; 1314 for (int i=0; i < count; i++) { 1315 FormSpec formSpec = (FormSpec) formSpecs.get(i); 1316 double weight = formSpec.getResizeWeight(); 1317 if (weight == FormSpec.NO_GROW) { 1318 sizes[i] = inputSizes[i]; 1319 } else { 1320 double roundingCorrection = restSpace - roundedRestSpace; 1321 double extraSpace = totalFreeSpace * weight / totalWeight; 1322 double correctedExtraSpace = extraSpace - roundingCorrection; 1323 int roundedExtraSpace = (int) Math.round(correctedExtraSpace); 1324 sizes[i] = inputSizes[i] + roundedExtraSpace; 1325 restSpace -= extraSpace; 1326 roundedRestSpace -= roundedExtraSpace; 1327 } 1328 } 1329 return sizes; 1330 } 1331 1332 1333 1339 private int sum(int[] sizes) { 1340 int sum = 0; 1341 for (int i = sizes.length - 1; i >=0; i--) { 1342 sum += sizes[i]; 1343 } 1344 return sum; 1345 } 1346 1347 private boolean containsSpecThatCanGrow(List formSpecs) { 1348 for (Iterator it = formSpecs.iterator(); it.hasNext();) { 1349 FormSpec formSpec = (FormSpec) it.next(); 1350 if (formSpec.canGrow()) 1351 return true; 1352 } 1353 return false; 1354 } 1355 1356 1357 1359 1364 static interface Measure { 1365 1366 1372 int sizeOf(Component component); 1373 } 1374 1375 1376 1380 private static abstract class CachingMeasure implements Measure { 1381 1382 protected final ComponentSizeCache cache; 1383 1384 private CachingMeasure(ComponentSizeCache cache) { 1385 this.cache = cache; 1386 } 1387 1388 } 1389 1390 private static class MinimumWidthMeasure extends CachingMeasure { 1392 private MinimumWidthMeasure(ComponentSizeCache cache) { 1393 super(cache); 1394 } 1395 public int sizeOf(Component c) { 1396 return cache.getMinimumSize(c).width; 1397 } 1398 } 1399 1400 private static class MinimumHeightMeasure extends CachingMeasure { 1402 private MinimumHeightMeasure(ComponentSizeCache cache) { 1403 super(cache); 1404 } 1405 public int sizeOf(Component c) { 1406 return cache.getMinimumSize(c).height; 1407 } 1408 } 1409 1410 private static class PreferredWidthMeasure extends CachingMeasure { 1412 private PreferredWidthMeasure(ComponentSizeCache cache) { 1413 super(cache); 1414 } 1415 public int sizeOf(Component c) { 1416 return cache.getPreferredSize(c).width; 1417 } 1418 } 1419 1420 private static class PreferredHeightMeasure extends CachingMeasure { 1422 private PreferredHeightMeasure(ComponentSizeCache cache) { 1423 super(cache); 1424 } 1425 public int sizeOf(Component c) { 1426 return cache.getPreferredSize(c).height; 1427 } 1428 } 1429 1430 1431 1433 1437 private static class ComponentSizeCache { 1438 1439 1440 private final Map minimumSizes; 1441 1442 1443 private final Map preferredSizes; 1444 1445 1449 private ComponentSizeCache(int initialCapacity) { 1450 minimumSizes = new HashMap(initialCapacity); 1451 preferredSizes = new HashMap(initialCapacity); 1452 } 1453 1454 1457 void invalidate() { 1458 minimumSizes.clear(); 1459 preferredSizes.clear(); 1460 } 1461 1462 1470 Dimension getMinimumSize(Component component) { 1471 Dimension size = (Dimension ) minimumSizes.get(component); 1472 if (size == null) { 1473 size = component.getMinimumSize(); 1474 minimumSizes.put(component, size); 1475 } 1476 return size; 1477 } 1478 1479 1487 Dimension getPreferredSize(Component component) { 1488 Dimension size = (Dimension ) preferredSizes.get(component); 1489 if (size == null) { 1490 size = component.getPreferredSize(); 1491 preferredSizes.put(component, size); 1492 } 1493 return size; 1494 } 1495 1496 void removeEntry(Component component) { 1497 minimumSizes.remove(component); 1498 preferredSizes.remove(component); 1499 } 1500 } 1501 1502 1503 1505 1518 public LayoutInfo getLayoutInfo(Container parent) { 1519 synchronized (parent.getTreeLock()) { 1520 initializeColAndRowComponentLists(); 1521 Dimension size = parent.getSize(); 1522 1523 Insets insets = parent.getInsets(); 1524 int totalWidth = size.width - insets.left - insets.right; 1525 int totalHeight = size.height- insets.top - insets.bottom; 1526 1527 int[] x = computeGridOrigins(parent, 1528 totalWidth, insets.left, 1529 colSpecs, 1530 colComponents, 1531 colGroupIndices, 1532 minimumWidthMeasure, 1533 preferredWidthMeasure 1534 ); 1535 int[] y = computeGridOrigins(parent, 1536 totalHeight, insets.top, 1537 rowSpecs, 1538 rowComponents, 1539 rowGroupIndices, 1540 minimumHeightMeasure, 1541 preferredHeightMeasure 1542 ); 1543 return new LayoutInfo(x, y); 1544 } 1545 } 1546 1547 1548 1551 public static final class LayoutInfo { 1552 1553 public final int[] columnOrigins; 1554 public final int[] rowOrigins; 1555 1556 private LayoutInfo(int[] xOrigins, int[] yOrigins) { 1557 this.columnOrigins = xOrigins; 1558 this.rowOrigins = yOrigins; 1559 } 1560 1561 public int getX() { 1562 return columnOrigins[0]; 1563 } 1564 1565 public int getY() { 1566 return rowOrigins[0]; 1567 } 1568 1569 public int getWidth() { 1570 return columnOrigins[columnOrigins.length-1] - columnOrigins[0]; 1571 } 1572 1573 public int getHeight() { 1574 return rowOrigins[rowOrigins.length-1] - rowOrigins[0]; 1575 } 1576 1577 } 1578 1579 1581 1589 private static ColumnSpec[] decodeColSpecs(String encodedColSpec) { 1590 if (encodedColSpec == null) 1591 throw new NullPointerException ("The column description must not be null."); 1592 1593 StringTokenizer tokenizer = new StringTokenizer(encodedColSpec, ", "); 1594 int columnCount = tokenizer.countTokens(); 1595 ColumnSpec[] colSpecs = new ColumnSpec[columnCount]; 1596 for (int i = 0; i < columnCount; i++) { 1597 colSpecs[i] = new ColumnSpec(tokenizer.nextToken()); 1598 } 1599 return colSpecs; 1600 } 1601 1602 1603 1611 private static RowSpec[] decodeRowSpecs(String encodedRowSpec) { 1612 if (encodedRowSpec == null) 1613 throw new NullPointerException ("The row description must not be null."); 1614 1615 StringTokenizer tokenizer = new StringTokenizer(encodedRowSpec, ", "); 1616 int rowCount = tokenizer.countTokens(); 1617 RowSpec[] rowSpecs = new RowSpec[rowCount]; 1618 for (int i = 0; i < rowCount; i++) { 1619 rowSpecs[i] = new RowSpec(tokenizer.nextToken()); 1620 } 1621 return rowSpecs; 1622 } 1623 1624 1625 1627 1634 private int[][] deepClone(int[][] array) { 1635 int[][] result = new int[array.length][]; 1636 for (int i = 0; i < result.length; i++) { 1637 result[i] = (int[]) array[i].clone(); 1638 } 1639 return result; 1640 } 1641 1642 1643 1645 1671 1672 1673} 1674 | Popular Tags |