Coverage Report - net.miginfocom.layout.Grid
 
Classes in this File Line Coverage Branch Coverage Complexity
Grid
N/A
N/A
7.924
Grid$1
N/A
N/A
7.924
Grid$Cell
N/A
N/A
7.924
Grid$CompWrap
N/A
N/A
7.924
Grid$FlowSizeSpec
N/A
N/A
7.924
Grid$LinkedDimGroup
N/A
N/A
7.924
 
 1  
 package net.miginfocom.layout;
 2  
 
 3  
 
 4  
 import java.util.*;
 5  
 /*
 6  
  * License (BSD):
 7  
  * ==============
 8  
  *
 9  
  * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com)
 10  
  * All rights reserved.
 11  
  *
 12  
  * Redistribution and use in source and binary forms, with or without modification,
 13  
  * are permitted provided that the following conditions are met:
 14  
  * Redistributions of source code must retain the above copyright notice, this list
 15  
  * of conditions and the following disclaimer.
 16  
  * Redistributions in binary form must reproduce the above copyright notice, this
 17  
  * list of conditions and the following disclaimer in the documentation and/or other
 18  
  * materials provided with the distribution.
 19  
  * Neither the name of the MiG InfoCom AB nor the names of its contributors may be
 20  
  * used to endorse or promote products derived from this software without specific
 21  
  * prior written permission.
 22  
  *
 23  
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 24  
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 25  
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 26  
  * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 27  
  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 28  
  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 29  
  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 30  
  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 31  
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 32  
  * OF SUCH DAMAGE.
 33  
  *
 34  
  * @version 1.0
 35  
  * @author Mikael Grev, MiG InfoCom AB
 36  
  *         Date: 2006-sep-08
 37  
  */
 38  
 
 39  
 /** Holds components in a grid. Does most of the logic behind the layout manager.
 40  
  */
 41  
 public final class Grid
 42  
 {
 43  
         public static final boolean TEST_GAPS = true;
 44  
 
 45  
         private static final Float[] GROW_100 = new Float[] {ResizeConstraint.WEIGHT_100};
 46  
 
 47  
         private static final DimConstraint DOCK_DIM_CONSTRAINT = new DimConstraint();
 48  
         static {
 49  
                 DOCK_DIM_CONSTRAINT.setGrowPriority(0);
 50  
         }
 51  
 
 52  
         /** This is the maximum grid position for "normal" components. Docking components use the space out to
 53  
          * <code>MAX_DOCK_GRID</code> and below 0.
 54  
          */
 55  
         private static final int MAX_GRID = 30000;
 56  
 
 57  
         /** Docking components will use the grid coordinates <code>-MAX_DOCK_GRID -> 0</code> and <code>MAX_GRID -> MAX_DOCK_GRID</code>.
 58  
          */
 59  
         private static final int MAX_DOCK_GRID = 32767;
 60  
 
 61  
         /** A constraint used for gaps.
 62  
          */
 63  
         private static final ResizeConstraint GAP_RC_CONST = new ResizeConstraint(200, ResizeConstraint.WEIGHT_100, 50, null);
 64  
         private static final ResizeConstraint GAP_RC_CONST_PUSH = new ResizeConstraint(200, ResizeConstraint.WEIGHT_100, 50, ResizeConstraint.WEIGHT_100);
 65  
 
 66  
         /** The constraints. Never <code>null</code>.
 67  
          */
 68  
         private final LC lc;
 69  
 
 70  
         /** The parent that is layout out and this grid is done for. Never <code>null</code>.
 71  
          */
 72  
         private final ContainerWrapper container;
 73  
 
 74  
         /** An x, y array implemented as a sparse array to accommodate for any grid size without wasting memory (or rather 15 bit (0-MAX_GRID * 0-MAX_GRID).
 75  
          */
 76  
         private final LinkedHashMap<Integer, Cell> grid = new LinkedHashMap<Integer, Cell>();   // [(y << 16) + x] -> Cell. null key for absolute positioned compwraps
 77  
 
 78  
         private HashMap<Integer, BoundSize> wrapGapMap = null;   // Row or Column index depending in the dimension that "wraps". Normally row indexes but may be column indexes if "flowy". 0 means before first row/col.
 79  
 
 80  
         /** The size of the grid. Row count and column count.
 81  
          */
 82  
         private final TreeSet<Integer> rowIndexes = new TreeSet<Integer>(), colIndexes = new TreeSet<Integer>();
 83  
 
 84  
         /** The row and column specifications.
 85  
          */
 86  
         private final AC rowConstr, colConstr;
 87  
 
 88  
         /** The in the constructor calculated min/pref/max sizes of the rows and columns.
 89  
          */
 90  
         private FlowSizeSpec colFlowSpecs = null, rowFlowSpecs = null;
 91  
 
 92  
         /** Components that are connections in one dimension (such as baseline alignment for instance) are grouped together and stored here.
 93  
          * One for each row/column.
 94  
          */
 95  
         private final ArrayList<LinkedDimGroup>[] colGroupLists, rowGroupLists;   //[(start)row/col number]
 96  
 
 97  
         /** The in the constructor calculated min/pref/max size of the whole grid.
 98  
          */
 99  
         private int[] width = null, height = null;
 100  
 
 101  
         /** If debug is on contains the bounds for things to paint when calling {@link ContainerWrapper#paintDebugCell(int, int, int, int)}
 102  
           */
 103  
         private ArrayList<int[]> debugRects = null; // [x, y, width, height]
 104  
 
 105  
         /** If any of the absolute coordinates for component bounds has links the name of the target is in this Set.
 106  
          * Since it requires some memory and computations this is checked at the creation so that
 107  
          * the link information is only created if needed later.
 108  
          * <p>
 109  
          * The boolean is true for groups id:s and null for normal id:s.
 110  
          */
 111  
         private HashMap<String, Boolean> linkTargetIDs = null;
 112  
 
 113  
         private final int dockOffY, dockOffX;
 114  
 
 115  
         private final Float[] pushXs, pushYs;
 116  
 
 117  
         private final ArrayList<LayoutCallback> callbackList;
 118  
 
 119  
         /** Constructor.
 120  
          * @param container The container that will be laid out.
 121  
          * @param lc The form flow constraints.
 122  
          * @param rowConstr The rows specifications. If more cell rows are required, the last element will be used for when there is no corresponding element in this array.
 123  
          * @param colConstr The columns specifications. If more cell rows are required, the last element will be used for when there is no corresponding element in this array.
 124  
          * @param ccMap The map containing the parsed constraints for each child component of <code>parent</code>. Will not be alterted.
 125  
          * @param callbackList A list of callbacks or <code>null</code> if none. Will not be alterted.
 126  
          */
 127  
         public Grid(ContainerWrapper container, LC lc, AC rowConstr, AC colConstr, Map<ComponentWrapper, CC> ccMap, ArrayList<LayoutCallback> callbackList)
 128  
         {
 129  
                 this.lc = lc;
 130  
                 this.rowConstr = rowConstr;
 131  
                 this.colConstr = colConstr;
 132  
                 this.container = container;
 133  
                 this.callbackList = callbackList;
 134  
 
 135  
                 int wrap = lc.getWrapAfter() != 0 ? lc.getWrapAfter() : (lc.isFlowX() ? colConstr : rowConstr).getConstaints().length;
 136  
 
 137  
                 final ComponentWrapper[] comps = container.getComponents();
 138  
 
 139  
                 boolean hasTagged = false;  // So we do not have to sort if it will not do any good
 140  
                 boolean hasPushX = false, hasPushY = false;
 141  
                 boolean hitEndOfRow = false;
 142  
                 final int[] cellXY = new int[2];
 143  
                 final ArrayList<int[]> spannedRects = new ArrayList<int[]>(2);
 144  
 
 145  
                 final DimConstraint[] specs = (lc.isFlowX() ? rowConstr : colConstr).getConstaints();
 146  
 
 147  
                 int sizeGroupsX = 0, sizeGroupsY = 0;
 148  
                 int[] dockInsets = null;    // top, left, bottom, right insets for docks.
 149  
 
 150  
                 LinkHandler.clearTemporaryBounds(container.getLayout());
 151  
 
 152  
                 for (int i = 0; i < comps.length;) {
 153  
                         ComponentWrapper comp = comps[i];
 154  
                         CC rootCc = getCC(comp, ccMap);
 155  
 
 156  
                         addLinkIDs(rootCc);
 157  
 
 158  
                         int hideMode = comp.isVisible() ? -1 : rootCc.getHideMode() != -1 ? rootCc.getHideMode() : lc.getHideMode();
 159  
 
 160  
                         if (hideMode == 3) { // To work with situations where there are components that does not have a layout manager, or not this one.
 161  
                                 setLinkedBounds(comp, rootCc, comp.getX(), comp.getY(), comp.getWidth(), comp.getHeight(), rootCc.isExternal());
 162  
                                 i++;
 163  
                                 continue;   // The "external" component should not be handled further.
 164  
                         }
 165  
 
 166  
                         if (rootCc.getHorizontal().getSizeGroup() != null)
 167  
                                 sizeGroupsX++;
 168  
                         if (rootCc.getVertical().getSizeGroup() != null)
 169  
                                 sizeGroupsY++;
 170  
 
 171  
                         // Special treatment of absolute positioned components.
 172  
                         UnitValue[] pos = getPos(comp, rootCc);
 173  
                         BoundSize[] cbSz = getCallbackSize(comp);
 174  
                         if (pos != null || rootCc.isExternal()) {
 175  
 
 176  
                                 CompWrap cw = new CompWrap(comp, rootCc, hideMode, pos, cbSz);
 177  
                                 Cell cell = grid.get(null);
 178  
                                 if (cell == null) {
 179  
                                         grid.put(null, new Cell(cw));
 180  
                                 } else {
 181  
                                         cell.compWraps.add(cw);
 182  
                                 }
 183  
 
 184  
                                 if (rootCc.isBoundsInGrid() == false || rootCc.isExternal()) {
 185  
                                         setLinkedBounds(comp, rootCc, comp.getX(), comp.getY(), comp.getWidth(), comp.getHeight(), rootCc.isExternal());
 186  
                                         i++;
 187  
                                         continue;
 188  
                                 }
 189  
                         }
 190  
 
 191  
                         if (rootCc.getDockSide() != -1) {
 192  
                                 if (dockInsets == null)
 193  
                                         dockInsets = new int[] {-MAX_DOCK_GRID, -MAX_DOCK_GRID, MAX_DOCK_GRID, MAX_DOCK_GRID};
 194  
 
 195  
                                 addDockingCell(dockInsets, rootCc.getDockSide(), new CompWrap(comp, rootCc, hideMode, pos, cbSz));
 196  
                                 i++;
 197  
                                 continue;
 198  
                         }
 199  
 
 200  
                         Boolean cellFlowX = rootCc.getFlowX();
 201  
                         Cell cell = null;
 202  
 
 203  
                         if (rootCc.isNewline()) {
 204  
                                 wrap(cellXY, rootCc.getNewlineGapSize());
 205  
                         } else if (hitEndOfRow) {
 206  
                                 wrap(cellXY, null);
 207  
                         }
 208  
                         hitEndOfRow = false;
 209  
 
 210  
                         final boolean rowNoGrid = lc.isNoGrid() || ((DimConstraint) LayoutUtil.getIndexSafe(specs, lc.isFlowX() ? cellXY[1] : cellXY[0])).isNoGrid();
 211  
 
 212  
                         // Move to a free y, x  if no absolute grid specified
 213  
                         int cx = rootCc.getCellX();
 214  
                         int cy = rootCc.getCellY();
 215  
                         if ((cx < 0 || cy < 0) && rowNoGrid == false && rootCc.getSkip() == 0) { // 3.7.2: If skip, don't find an empty cell first.
 216  
                                 while (isCellFree(cellXY[1], cellXY[0], spannedRects) == false) {
 217  
                                         if (Math.abs(increase(cellXY, 1)) >= wrap)
 218  
                                                 wrap(cellXY, null);
 219  
                                 }
 220  
                         } else {
 221  
                                 if (cx >= 0 && cy >= 0) {
 222  
                                         if (cy >= 0) {
 223  
                                                 cellXY[0] = cx;
 224  
                                                 cellXY[1] = cy;
 225  
                                         } else {    // Only one coordinate is specified. Use the current row (flowx) or column (flowy) to fill in.
 226  
                                                 if (lc.isFlowX()) {
 227  
                                                         cellXY[0] = cx;
 228  
                                                 } else {
 229  
                                                         cellXY[1] = cx;
 230  
                                                 }
 231  
                                         }
 232  
                                 }
 233  
                                 cell = getCell(cellXY[1], cellXY[0]);   // Might be null
 234  
                         }
 235  
 
 236  
                         // Skip a number of cells. Changed for 3.6.1 to take wrap into account and thus "skip" to the next and possibly more rows.
 237  
                         for (int s = 0, skipCount = rootCc.getSkip(); s < skipCount; s++) {
 238  
                                 do {
 239  
                                         if (Math.abs(increase(cellXY, 1)) >= wrap)
 240  
                                                 wrap(cellXY, null);
 241  
                                 } while (isCellFree(cellXY[1], cellXY[0], spannedRects) == false);
 242  
                         }
 243  
 
 244  
                         // If cell is not created yet, create it and set it.
 245  
                         if (cell == null) {
 246  
                                 int spanx = Math.min(rowNoGrid && lc.isFlowX() ? LayoutUtil.INF : rootCc.getSpanX(), MAX_GRID - cellXY[0]);
 247  
                                 int spany = Math.min(rowNoGrid && !lc.isFlowX() ? LayoutUtil.INF : rootCc.getSpanY(), MAX_GRID - cellXY[1]);
 248  
 
 249  
                                 cell = new Cell(spanx, spany, cellFlowX != null ? cellFlowX : lc.isFlowX());
 250  
 
 251  
                                 setCell(cellXY[1], cellXY[0], cell);
 252  
 
 253  
                                 // Add a rectangle so we can know that spanned cells occupy more space.
 254  
                                 if (spanx > 1 || spany > 1)
 255  
                                         spannedRects.add(new int[] {cellXY[0], cellXY[1], spanx, spany});
 256  
                         }
 257  
 
 258  
                         // Add the one, or all, components that split the grid position to the same Cell.
 259  
                         boolean wrapHandled = false;
 260  
                         int splitLeft = rowNoGrid ? LayoutUtil.INF : rootCc.getSplit() - 1;
 261  
                         boolean splitExit = false;
 262  
                         final boolean spanRestOfRow = (lc.isFlowX() ? rootCc.getSpanX() : rootCc.getSpanY()) == LayoutUtil.INF;
 263  
 
 264  
                         for (; splitLeft >= 0 && i < comps.length; splitLeft--) {
 265  
                                 ComponentWrapper compAdd = comps[i];
 266  
                                 CC cc = getCC(compAdd, ccMap);
 267  
 
 268  
                                 addLinkIDs(cc);
 269  
 
 270  
                                 boolean visible = compAdd.isVisible();
 271  
                                 hideMode = visible ? -1 : cc.getHideMode() != -1 ? cc.getHideMode() : lc.getHideMode();
 272  
 
 273  
                                 if (cc.isExternal() || hideMode == 3) {
 274  
                                         i++;
 275  
                                         splitLeft++;    // Added for 3.5.5 so that these components does not "take" a split slot.
 276  
                                         continue;       // To work with situations where there are components that does not have a layout manager, or not this one.
 277  
                                 }
 278  
 
 279  
                                 hasPushX |= (visible || hideMode > 1) && (cc.getPushX() != null);
 280  
                                 hasPushY |= (visible || hideMode > 1) && (cc.getPushY() != null);
 281  
 
 282  
                                 if (cc != rootCc) { // If not first in a cell
 283  
                                         if (cc.isNewline() || cc.isBoundsInGrid() == false || cc.getDockSide() != -1)
 284  
                                                 break;
 285  
 
 286  
                                         if (splitLeft > 0 && cc.getSkip() > 0) {
 287  
                                                 splitExit = true;
 288  
                                                 break;
 289  
                                         }
 290  
 
 291  
                                         pos = getPos(compAdd, cc);
 292  
                                         cbSz = getCallbackSize(compAdd);
 293  
                                 }
 294  
 
 295  
                                 CompWrap cw = new CompWrap(compAdd, cc, hideMode, pos, cbSz);
 296  
                                 cell.compWraps.add(cw);
 297  
                                 cell.hasTagged |= cc.getTag() != null;
 298  
                                 hasTagged |= cell.hasTagged;
 299  
 
 300  
                                 if (cc != rootCc) {
 301  
                                         if (cc.getHorizontal().getSizeGroup() != null)
 302  
                                                 sizeGroupsX++;
 303  
                                         if (cc.getVertical().getSizeGroup() != null)
 304  
                                                 sizeGroupsY++;
 305  
                                 }
 306  
 
 307  
                                 i++;
 308  
 
 309  
                                 if ((cc.isWrap() || (spanRestOfRow && splitLeft == 0))) {
 310  
                                         if (cc.isWrap()) {
 311  
                                                 wrap(cellXY, cc.getWrapGapSize());
 312  
                                         } else {
 313  
                                                 hitEndOfRow = true;
 314  
                                         }
 315  
                                         wrapHandled = true;
 316  
                                         break;
 317  
                                 }
 318  
                         }
 319  
 
 320  
                         if (wrapHandled == false && rowNoGrid == false) {
 321  
                                 int span = lc.isFlowX() ? cell.spanx : cell.spany;
 322  
                                 if (Math.abs((lc.isFlowX() ? cellXY[0] : cellXY[1])) + span >= wrap) {
 323  
                                         hitEndOfRow = true;
 324  
                                 } else {
 325  
                                         increase(cellXY, splitExit ? span - 1 : span);
 326  
                                 }
 327  
                         }
 328  
                 }
 329  
 
 330  
                 // If there were size groups, calculate the largest values in the groups (for min/pref/max) and enforce them on the rest in the group.
 331  
                 if (sizeGroupsX > 0 || sizeGroupsY > 0) {
 332  
                         HashMap<String, int[]> sizeGroupMapX = sizeGroupsX > 0 ? new HashMap<String, int[]>(sizeGroupsX) : null;
 333  
                         HashMap<String, int[]> sizeGroupMapY = sizeGroupsY > 0 ? new HashMap<String, int[]>(sizeGroupsY) : null;
 334  
                         ArrayList<CompWrap> sizeGroupCWs = new ArrayList<CompWrap>(Math.max(sizeGroupsX, sizeGroupsY));
 335  
 
 336  
                         for (Cell cell : grid.values()) {
 337  
                                 for (int i = 0; i < cell.compWraps.size(); i++) {
 338  
                                         CompWrap cw = cell.compWraps.get(i);
 339  
                                         String sgx = cw.cc.getHorizontal().getSizeGroup();
 340  
                                         String sgy = cw.cc.getVertical().getSizeGroup();
 341  
 
 342  
                                         if (sgx != null || sgy != null) {
 343  
                                                 if (sgx != null && sizeGroupMapX != null)
 344  
                                                         addToSizeGroup(sizeGroupMapX, sgx, cw.horSizes);
 345  
                                                 if (sgy != null && sizeGroupMapY != null)
 346  
                                                         addToSizeGroup(sizeGroupMapY, sgy, cw.verSizes);
 347  
                                                 sizeGroupCWs.add(cw);
 348  
                                         }
 349  
                                 }
 350  
                         }
 351  
 
 352  
                         // Set/equalize the sizeGroups to same the values.
 353  
                         for (CompWrap cw : sizeGroupCWs) {
 354  
                                 if (sizeGroupMapX != null)
 355  
                                         cw.setSizes(sizeGroupMapX.get(cw.cc.getHorizontal().getSizeGroup()), true);  // Target method handles null sizes
 356  
                                 if (sizeGroupMapY != null)
 357  
                                         cw.setSizes(sizeGroupMapY.get(cw.cc.getVertical().getSizeGroup()), false); // Target method handles null sizes
 358  
                         }
 359  
                 } // Component loop
 360  
 
 361  
                 // If there were size groups, calculate the largest values in the groups (for min/pref/max) and enforce them on the rest in the group.
 362  
                 if (sizeGroupsX > 0 || sizeGroupsY > 0) {
 363  
                         HashMap<String, int[]> sizeGroupMapX = sizeGroupsX > 0 ? new HashMap<String, int[]>(sizeGroupsX) : null;
 364  
                         HashMap<String, int[]> sizeGroupMapY = sizeGroupsY > 0 ? new HashMap<String, int[]>(sizeGroupsY) : null;
 365  
                         ArrayList<CompWrap> sizeGroupCWs = new ArrayList<CompWrap>(Math.max(sizeGroupsX, sizeGroupsY));
 366  
 
 367  
                         for (Cell cell : grid.values()) {
 368  
                                 for (int i = 0; i < cell.compWraps.size(); i++) {
 369  
                                         CompWrap cw = cell.compWraps.get(i);
 370  
                                         String sgx = cw.cc.getHorizontal().getSizeGroup();
 371  
                                         String sgy = cw.cc.getVertical().getSizeGroup();
 372  
 
 373  
                                         if (sgx != null || sgy != null) {
 374  
                                                 if (sgx != null && sizeGroupMapX != null)
 375  
                                                         addToSizeGroup(sizeGroupMapX, sgx, cw.horSizes);
 376  
                                                 if (sgy != null && sizeGroupMapY != null)
 377  
                                                         addToSizeGroup(sizeGroupMapY, sgy, cw.verSizes);
 378  
                                                 sizeGroupCWs.add(cw);
 379  
                                         }
 380  
                                 }
 381  
                         }
 382  
 
 383  
                         // Set/equalize the sizeGroups to same the values.
 384  
                         for (CompWrap cw : sizeGroupCWs) {
 385  
                                 if (sizeGroupMapX != null)
 386  
                                         cw.setSizes(sizeGroupMapX.get(cw.cc.getHorizontal().getSizeGroup()), true);  // Target method handles null sizes
 387  
                                 if (sizeGroupMapY != null)
 388  
                                         cw.setSizes(sizeGroupMapY.get(cw.cc.getVertical().getSizeGroup()), false); // Target method handles null sizes
 389  
                         }
 390  
                 }
 391  
 
 392  
                 if (hasTagged)
 393  
                         sortCellsByPlatform(grid.values(), container);
 394  
 
 395  
                 // Calculate gaps now that the cells are filled and we know all adjacent components.
 396  
                 boolean ltr = LayoutUtil.isLeftToRight(lc, container);
 397  
                 for (Cell cell : grid.values()) {
 398  
                         ArrayList<CompWrap> cws = cell.compWraps;
 399  
 
 400  
                         for (int i = 0, lastI = cws.size() - 1; i <= lastI; i++) {
 401  
                                 CompWrap cw = cws.get(i);
 402  
                                 ComponentWrapper cwBef = i > 0 ? cws.get(i - 1).comp : null;
 403  
                                 ComponentWrapper cwAft = i < lastI ? cws.get(i + 1).comp : null;
 404  
 
 405  
                                 String tag = getCC(cw.comp, ccMap).getTag();
 406  
                                 CC ccBef = cwBef != null ? getCC(cwBef, ccMap) : null;
 407  
                                 CC ccAft = cwAft != null ? getCC(cwAft, ccMap) : null;
 408  
 
 409  
                                 cw.calcGaps(cwBef, ccBef, cwAft, ccAft, tag, cell.flowx, ltr);
 410  
                         }
 411  
                 }
 412  
 
 413  
                 dockOffX = getDockInsets(colIndexes);
 414  
                 dockOffY = getDockInsets(rowIndexes);
 415  
 
 416  
                 // Add synthetic indexes for empty rows and columns so they can get a size
 417  
                 for (int i = 0, iSz = rowConstr.getCount(); i < iSz; i++)
 418  
                         rowIndexes.add(i);
 419  
                 for (int i = 0, iSz = colConstr.getCount(); i < iSz; i++)
 420  
                         colIndexes.add(i);
 421  
 
 422  
                 colGroupLists = divideIntoLinkedGroups(false);
 423  
                 rowGroupLists = divideIntoLinkedGroups(true);
 424  
 
 425  
                 pushXs = hasPushX || lc.isFillX() ? getDefaultPushWeights(false) : null;
 426  
                 pushYs = hasPushY || lc.isFillY() ? getDefaultPushWeights(true) : null;
 427  
 
 428  
                 if (LayoutUtil.isDesignTime(container))
 429  
                         saveGrid(container, grid);
 430  
         }
 431  
 
 432  
         private static CC getCC(ComponentWrapper comp, Map<ComponentWrapper, CC> ccMap)
 433  
         {
 434  
                 CC cc = ccMap.get(comp);
 435  
                 return cc != null ? cc : new CC();
 436  
         }
 437  
 
 438  
         private void addLinkIDs(CC cc)
 439  
         {
 440  
                 String[] linkIDs = cc.getLinkTargets();
 441  
                 for (String linkID : linkIDs) {
 442  
                         if (linkTargetIDs == null)
 443  
                                 linkTargetIDs = new HashMap<String, Boolean>();
 444  
                         linkTargetIDs.put(linkID, null);
 445  
                 }
 446  
         }
 447  
 
 448  
         /** If the container (parent) that this grid is laying out has changed its bounds, call this method to
 449  
          * clear any cached values.
 450  
          */
 451  
         public void invalidateContainerSize()
 452  
         {
 453  
                 colFlowSpecs = null;
 454  
         }
 455  
 
 456  
         /** Does the actual layout. Uses many values calculated in the constructor.
 457  
          * @param bounds The bounds to layout against. Normally that of the parent. [x, y, width, height].
 458  
          * @param alignX The alignment for the x-axis.
 459  
          * @param alignY The alignment for the y-axis.
 460  
          * @param debug If debug information should be saved in {@link #debugRects}.
 461  
          * @param checkPrefChange If a check should be done to see if the setting of any new bounds changes the preferred size
 462  
          * of a component.
 463  
          * @return If the layout has probably changed the preferred size and there is need for a new layout (normally only SWT).
 464  
          */
 465  
         public boolean layout(int[] bounds, UnitValue alignX, UnitValue alignY, boolean debug, boolean checkPrefChange)
 466  
         {
 467  
                 if (debug)
 468  
                         debugRects = new ArrayList<int[]>();
 469  
 
 470  
                 checkSizeCalcs();
 471  
 
 472  
                 resetLinkValues(true, true);
 473  
 
 474  
                 layoutInOneDim(bounds[2], alignX, false, pushXs);
 475  
                 layoutInOneDim(bounds[3], alignY, true, pushYs);
 476  
 
 477  
                 HashMap<String, Integer> endGrpXMap = null, endGrpYMap = null;
 478  
                 int compCount = container.getComponentCount();
 479  
 
 480  
                 // Transfer the calculated bound from the ComponentWrappers to the actual Components.
 481  
                 boolean layoutAgain = false;
 482  
                 if (compCount > 0) {
 483  
                         for (int j = 0; j < (linkTargetIDs != null ? 2 : 1); j++) {   // First do the calculations (maybe more than once) then set the bounds when done
 484  
                                 boolean doAgain;
 485  
                                 int count = 0;
 486  
                                 do {
 487  
                                         doAgain = false;
 488  
                                         for (Cell cell : grid.values()) {
 489  
                                                 ArrayList<CompWrap> compWraps = cell.compWraps;
 490  
                                                 for (int i = 0, iSz = compWraps.size(); i < iSz; i++) {
 491  
                                                         CompWrap cw = compWraps.get(i);
 492  
 
 493  
                                                         if (j == 0) {
 494  
                                                                 doAgain |= doAbsoluteCorrections(cw, bounds);
 495  
                                                                 if (doAgain == false) { // If we are going to do this again, do not bother this time around
 496  
                                                                         if (cw.cc.getHorizontal().getEndGroup() != null)
 497  
                                                                                 endGrpXMap = addToEndGroup(endGrpXMap, cw.cc.getHorizontal().getEndGroup(), cw.x + cw.w);
 498  
                                                                         if (cw.cc.getVertical().getEndGroup() != null)
 499  
                                                                                 endGrpYMap = addToEndGroup(endGrpYMap, cw.cc.getVertical().getEndGroup(), cw.y + cw.h);
 500  
                                                                 }
 501  
 
 502  
                                                                 // @since 3.7.2 Needed or absolute "pos" pointing to "visual" or "container" didn't work if
 503  
                                                                 // their bounds changed during the layout cycle. At least not in SWT.
 504  
                                                                 if (linkTargetIDs != null && (linkTargetIDs.containsKey("visual") || linkTargetIDs.containsKey("container")))
 505  
                                                                         layoutAgain = true;
 506  
                                                         }
 507  
 
 508  
                                                         if (linkTargetIDs == null || j == 1) {
 509  
                                                                 if (cw.cc.getHorizontal().getEndGroup() != null)
 510  
                                                                         cw.w = endGrpXMap.get(cw.cc.getHorizontal().getEndGroup()) - cw.x;
 511  
                                                                 if (cw.cc.getVertical().getEndGroup() != null)
 512  
                                                                         cw.h = endGrpYMap.get(cw.cc.getVertical().getEndGroup()) - cw.y;
 513  
 
 514  
                                                                 cw.x += bounds[0];
 515  
                                                                 cw.y += bounds[1];
 516  
                                                                 layoutAgain |= cw.transferBounds(checkPrefChange && !layoutAgain);
 517  
 
 518  
                                                                 if (callbackList != null) {
 519  
                                                                         for (LayoutCallback callback : callbackList)
 520  
                                                                                 callback.correctBounds(cw.comp);
 521  
                                                                 }
 522  
                                                         }
 523  
                                                 }
 524  
                                         }
 525  
                                         clearGroupLinkBounds();
 526  
                                         if (++count > ((compCount << 3) + 10)) {
 527  
                                                 System.err.println("Unstable cyclic dependency in absolute linked values!");
 528  
                                                 break;
 529  
                                         }
 530  
 
 531  
                                 } while (doAgain);
 532  
                         }
 533  
                 }
 534  
 
 535  
                 // Add debug shapes for the "cells". Use the CompWraps as base for inding the cells.
 536  
                 if (debug) {
 537  
                         for (Cell cell : grid.values()) {
 538  
                                 ArrayList<CompWrap> compWraps = cell.compWraps;
 539  
                                 for (int i = 0, iSz = compWraps.size(); i < iSz; i++) {
 540  
                                         CompWrap cw = compWraps.get(i);
 541  
                                         LinkedDimGroup hGrp = getGroupContaining(colGroupLists, cw);
 542  
                                         LinkedDimGroup vGrp = getGroupContaining(rowGroupLists, cw);
 543  
 
 544  
                                         if (hGrp != null && vGrp != null)
 545  
                                                 debugRects.add(new int[]{hGrp.lStart + bounds[0] - (hGrp.fromEnd ? hGrp.lSize : 0), vGrp.lStart + bounds[1] - (vGrp.fromEnd ? vGrp.lSize : 0), hGrp.lSize, vGrp.lSize});
 546  
                                 }
 547  
                         }
 548  
                 }
 549  
                 return layoutAgain;
 550  
         }
 551  
 
 552  
         public void paintDebug()
 553  
         {
 554  
                 if (debugRects != null) {
 555  
                         container.paintDebugOutline();
 556  
 
 557  
                         ArrayList<int[]> painted = new ArrayList<int[]>();
 558  
                         for (int i = 0, iSz = debugRects.size(); i < iSz; i++) {
 559  
                                 int[] r = debugRects.get(i);
 560  
                                 if (painted.contains(r) == false) {
 561  
                                         container.paintDebugCell(r[0], r[1], r[2], r[3]);
 562  
                                         painted.add(r);
 563  
                                 }
 564  
                         }
 565  
 
 566  
                         for (Cell cell : grid.values()) {
 567  
                                 ArrayList<CompWrap> compWraps = cell.compWraps;
 568  
                                 for (int i = 0, iSz = compWraps.size(); i < iSz; i++)
 569  
                                         compWraps.get(i).comp.paintDebugOutline();
 570  
                         }
 571  
                 }
 572  
         }
 573  
 
 574  
         public ContainerWrapper getContainer()
 575  
         {
 576  
                 return container;
 577  
         }
 578  
 
 579  
         public final int[] getWidth()
 580  
         {
 581  
                 checkSizeCalcs();
 582  
                 return width.clone();
 583  
         }
 584  
 
 585  
         public final int[] getHeight()
 586  
         {
 587  
                 checkSizeCalcs();
 588  
                 return height.clone();
 589  
         }
 590  
 
 591  
         private void checkSizeCalcs()
 592  
         {
 593  
                 if (colFlowSpecs == null) {
 594  
 
 595  
                         colFlowSpecs = calcRowsOrColsSizes(true);
 596  
                         rowFlowSpecs = calcRowsOrColsSizes(false);
 597  
 
 598  
                         width = getMinPrefMaxSumSize(true);
 599  
                         height = getMinPrefMaxSumSize(false);
 600  
 
 601  
                         if (linkTargetIDs == null) {
 602  
                                 resetLinkValues(false, true);
 603  
                         } else {
 604  
                                 // This call makes some components flicker on SWT. They get their bounds changed twice since
 605  
                                 // the change might affect the absolute size adjustment below. There's no way around this that
 606  
                                 // I know of.
 607  
                                 layout(new int[4], null, null, false, false);
 608  
                                 resetLinkValues(false, false);
 609  
                         }
 610  
 
 611  
                         adjustSizeForAbsolute(true);
 612  
                         adjustSizeForAbsolute(false);
 613  
                 }
 614  
         }
 615  
 
 616  
         private UnitValue[] getPos(ComponentWrapper cw, CC cc)
 617  
         {
 618  
                 UnitValue[] cbPos = null;
 619  
                 if (callbackList != null) {
 620  
                         for (int i = 0; i < callbackList.size() && cbPos == null; i++)
 621  
                                 cbPos = callbackList.get(i).getPosition(cw);   // NOT a copy!
 622  
                 }
 623  
 
 624  
                 // If one is null, return the other (which many also be null)
 625  
                 UnitValue[] ccPos = cc.getPos();    // A copy!!
 626  
                 if (cbPos == null || ccPos == null)
 627  
                         return cbPos != null ? cbPos : ccPos;
 628  
 
 629  
                 // Merge
 630  
                 for (int i = 0; i < 4; i++) {
 631  
                         UnitValue cbUv = cbPos[i];
 632  
                         if (cbUv != null)
 633  
                                 ccPos[i] = cbUv;
 634  
                 }
 635  
 
 636  
                 return ccPos;
 637  
         }
 638  
 
 639  
         private BoundSize[] getCallbackSize(ComponentWrapper cw)
 640  
         {
 641  
                 if (callbackList != null) {
 642  
                         for (LayoutCallback callback : callbackList) {
 643  
                                 BoundSize[] bs = callback.getSize(cw);   // NOT a copy!
 644  
                                 if (bs != null)
 645  
                                         return bs;
 646  
                         }
 647  
                 }
 648  
                 return null;
 649  
         }
 650  
 
 651  
         private static int getDockInsets(TreeSet<Integer> set)
 652  
         {
 653  
                 int c = 0;
 654  
                 for (Integer i : set) {
 655  
                         if (i < -MAX_GRID) {
 656  
                                 c++;
 657  
                         } else {
 658  
                                 break;  // Since they are sorted we can break
 659  
                         }
 660  
                 }
 661  
                 return c;
 662  
         }
 663  
 
 664  
         /**
 665  
          * @param cw Never <code>null</code>.
 666  
          * @param cc Never <code>null</code>.
 667  
          * @param external The bounds should be stored even if they are not in {@link #linkTargetIDs}.
 668  
          * @return If a change has been made.
 669  
          */
 670  
         private boolean setLinkedBounds(ComponentWrapper cw, CC cc, int x, int y, int w, int h, boolean external)
 671  
         {
 672  
                 String id = cc.getId() != null ? cc.getId() : cw.getLinkId();
 673  
                 if (id == null)
 674  
                         return false;
 675  
 
 676  
                 String gid = null;
 677  
                 int grIx = id.indexOf('.');
 678  
                 if (grIx != -1 ) {
 679  
                         gid = id.substring(0, grIx);
 680  
                         id = id.substring(grIx + 1);
 681  
                 }
 682  
 
 683  
                 Object lay = container.getLayout();
 684  
                 boolean changed = false;
 685  
                 if (external || (linkTargetIDs != null && linkTargetIDs.containsKey(id)))
 686  
                         changed = LinkHandler.setBounds(lay, id, x, y, w, h, !external, false);
 687  
 
 688  
                 if (gid != null && (external || (linkTargetIDs != null && linkTargetIDs.containsKey(gid)))) {
 689  
                         if (linkTargetIDs == null)
 690  
                                 linkTargetIDs = new HashMap<String, Boolean>(4);
 691  
 
 692  
                         linkTargetIDs.put(gid, Boolean.TRUE);
 693  
                         changed |= LinkHandler.setBounds(lay, gid, x, y, w, h, !external, true);
 694  
                 }
 695  
 
 696  
                 return changed;
 697  
         }
 698  
 
 699  
         /** Go to next cell.
 700  
          * @param p The point to increase
 701  
          * @param cnt How many cells to advance.
 702  
          * @return The new value in the "incresing" dimension.
 703  
          */
 704  
         private int increase(int[] p, int cnt)
 705  
         {
 706  
                 return lc.isFlowX() ? (p[0] += cnt) : (p[1] += cnt);
 707  
         }
 708  
 
 709  
         /** Wraps to the next row or column depending on if horizontal flow or vertical flow is used.
 710  
          * @param cellXY The point to wrap and thus set either x or y to 0 and increase the other one.
 711  
          * @param gapSize The gaps size specified in a "wrap XXX" or "newline XXX" or <code>null</code> if none.
 712  
          */
 713  
         private void wrap(int[] cellXY, BoundSize gapSize)
 714  
         {
 715  
                 boolean flowx = lc.isFlowX();
 716  
                 cellXY[0] = flowx ? 0 : cellXY[0] + 1;
 717  
                 cellXY[1] = flowx ? cellXY[1] + 1 : 0;
 718  
 
 719  
                 if (gapSize != null) {
 720  
                         if (wrapGapMap == null)
 721  
                                 wrapGapMap = new HashMap<Integer, BoundSize>(8);
 722  
 
 723  
                         wrapGapMap.put(cellXY[flowx ? 1 : 0], gapSize);
 724  
                 }
 725  
 
 726  
                 // add the row/column so that the gap in the last row/col will not be removed.
 727  
                 if (flowx) {
 728  
                         rowIndexes.add(cellXY[1]);
 729  
                 } else {
 730  
                         colIndexes.add(cellXY[0]);
 731  
                 }
 732  
         }
 733  
 
 734  
         /** Sort components (normally buttons in a button bar) so they appear in the correct order.
 735  
          * @param cells The cells to sort.
 736  
          * @param parent The parent.
 737  
          */
 738  
         private static void sortCellsByPlatform(Collection<Cell> cells, ContainerWrapper parent)
 739  
         {
 740  
                 String order = PlatformDefaults.getButtonOrder();
 741  
                 String orderLo = order.toLowerCase();
 742  
 
 743  
                 int unrelSize = PlatformDefaults.convertToPixels(1, "u", true, 0, parent, null);
 744  
 
 745  
                 if (unrelSize == UnitConverter.UNABLE)
 746  
                         throw new IllegalArgumentException("'unrelated' not recognized by PlatformDefaults!");
 747  
 
 748  
                 int[] gapUnrel = new int[] {unrelSize, unrelSize, LayoutUtil.NOT_SET};
 749  
                 int[] flGap = new int[] {0, 0, LayoutUtil.NOT_SET};
 750  
 
 751  
                 for (Cell cell : cells) {
 752  
                         if (cell.hasTagged == false)
 753  
                                 continue;
 754  
 
 755  
                         CompWrap prevCW = null;
 756  
                         boolean nextUnrel = false;
 757  
                         boolean nextPush = false;
 758  
                         ArrayList<CompWrap> sortedList = new ArrayList<CompWrap>(cell.compWraps.size());
 759  
 
 760  
                         for (int i = 0, iSz = orderLo.length(); i < iSz; i++) {
 761  
                                 char c = orderLo.charAt(i);
 762  
                                 if (c == '+' || c == '_') {
 763  
                                         nextUnrel = true;
 764  
                                         if (c == '+')
 765  
                                                 nextPush = true;
 766  
                                 } else {
 767  
                                         String tag = PlatformDefaults.getTagForChar(c);
 768  
                                         if (tag != null) {
 769  
                                                 for (int j = 0, jSz = cell.compWraps.size(); j < jSz; j++) {
 770  
                                                         CompWrap cw = cell.compWraps.get(j);
 771  
                                                         if (tag.equals(cw.cc.getTag())) {
 772  
                                                                 if (Character.isUpperCase(order.charAt(i))) {
 773  
                                                                         int min = PlatformDefaults.getMinimumButtonWidth().getPixels(0, parent, cw.comp);
 774  
                                                                         if (min > cw.horSizes[LayoutUtil.MIN])
 775  
                                                                                 cw.horSizes[LayoutUtil.MIN] = min;
 776  
 
 777  
                                                                         correctMinMax(cw.horSizes);
 778  
                                                                 }
 779  
 
 780  
                                                                 sortedList.add(cw);
 781  
 
 782  
                                                                 if (nextUnrel) {
 783  
                                                                         (prevCW != null ? prevCW : cw).mergeGapSizes(gapUnrel, cell.flowx, prevCW == null);
 784  
                                                                         if (nextPush) {
 785  
                                                                                 cw.forcedPushGaps = 1;
 786  
                                                                                 nextUnrel = false;
 787  
                                                                                 nextPush = false;
 788  
                                                                         }
 789  
                                                                 }
 790  
 
 791  
                                                                 // "unknown" components will always get an Unrelated gap.
 792  
                                                                 if (c == 'u')
 793  
                                                                         nextUnrel = true;
 794  
                                                                 prevCW = cw;
 795  
                                                         }
 796  
                                                 }
 797  
                                         }
 798  
                                 }
 799  
                         }
 800  
 
 801  
                         // If we have a gap that was supposed to push but no more components was found to but the "gap before" then compensate.
 802  
                         if (sortedList.size() > 0) {
 803  
                                 CompWrap cw = sortedList.get(sortedList.size() - 1);
 804  
                                 if (nextUnrel) {
 805  
                                         cw.mergeGapSizes(gapUnrel, cell.flowx, false);
 806  
                                         if (nextPush)
 807  
                                                 cw.forcedPushGaps |= 2;
 808  
                                 }
 809  
 
 810  
                                 // Remove first and last gap if not set explicitly.
 811  
                                 if (cw.cc.getHorizontal().getGapAfter() == null)
 812  
                                         cw.setGaps(flGap, 3);
 813  
 
 814  
                                 cw = sortedList.get(0);
 815  
                                 if (cw.cc.getHorizontal().getGapBefore() == null)
 816  
                                         cw.setGaps(flGap, 1);
 817  
                         }
 818  
 
 819  
                         // Exchange the unsorted CompWraps for the sorted one.
 820  
                         if (cell.compWraps.size() == sortedList.size()) {
 821  
                                 cell.compWraps.clear();
 822  
                         } else {
 823  
                                 cell.compWraps.removeAll(sortedList);
 824  
                         }
 825  
                         cell.compWraps.addAll(sortedList);
 826  
                 }
 827  
         }
 828  
 
 829  
         private Float[] getDefaultPushWeights(boolean isRows)
 830  
         {
 831  
                 ArrayList<LinkedDimGroup>[] groupLists = isRows ? rowGroupLists : colGroupLists;
 832  
 
 833  
                 Float[] pushWeightArr = GROW_100;   // Only create specific if any of the components have grow.
 834  
                 for (int i = 0, ix = 1; i < groupLists.length; i++, ix += 2) {
 835  
                         ArrayList<LinkedDimGroup> grps = groupLists[i];
 836  
                         Float rowPushWeight = null;
 837  
                         for (LinkedDimGroup grp : grps) {
 838  
                                 for (int c = 0; c < grp._compWraps.size(); c++) {
 839  
                                         CompWrap cw = grp._compWraps.get(c);
 840  
                                         int hideMode = cw.comp.isVisible() ? -1 : cw.cc.getHideMode() != -1 ? cw.cc.getHideMode() : lc.getHideMode();
 841  
 
 842  
                                         Float pushWeight = hideMode < 2 ? (isRows ? cw.cc.getPushY() : cw.cc.getPushX()) : null;
 843  
                                         if (rowPushWeight == null || (pushWeight != null && pushWeight.floatValue() > rowPushWeight.floatValue()))
 844  
                                                 rowPushWeight = pushWeight;
 845  
                                 }
 846  
                         }
 847  
 
 848  
                         if (rowPushWeight != null) {
 849  
                                 if (pushWeightArr == GROW_100)
 850  
                                         pushWeightArr = new Float[(groupLists.length << 1) + 1];
 851  
                                 pushWeightArr[ix] = rowPushWeight;
 852  
                         }
 853  
                 }
 854  
 
 855  
                 return pushWeightArr;
 856  
         }
 857  
 
 858  
         private void clearGroupLinkBounds()
 859  
         {
 860  
                 if (linkTargetIDs == null)
 861  
                         return;
 862  
 
 863  
                 for (Map.Entry<String, Boolean> o : linkTargetIDs.entrySet()) {
 864  
                         if (o.getValue() == Boolean.TRUE)
 865  
                                 LinkHandler.clearBounds(container.getLayout(), o.getKey());
 866  
                 }
 867  
         }
 868  
 
 869  
         private void resetLinkValues(boolean parentSize, boolean compLinks)
 870  
         {
 871  
                 Object lay = container.getLayout();
 872  
                 if (compLinks)
 873  
                         LinkHandler.clearTemporaryBounds(lay);
 874  
 
 875  
                 boolean defIns = !hasDocks();
 876  
 
 877  
                 int parW = parentSize ? lc.getWidth().constrain(container.getWidth(), getParentSize(container, true), container) : 0;
 878  
                 int parH = parentSize ? lc.getHeight().constrain(container.getHeight(), getParentSize(container, false), container) : 0;
 879  
 
 880  
                 int insX = LayoutUtil.getInsets(lc, 0, defIns).getPixels(0, container, null);
 881  
                 int insY = LayoutUtil.getInsets(lc, 1, defIns).getPixels(0, container, null);
 882  
                 int visW = parW - insX - LayoutUtil.getInsets(lc, 2, defIns).getPixels(0, container, null);
 883  
                 int visH = parH - insY - LayoutUtil.getInsets(lc, 3, defIns).getPixels(0, container, null);
 884  
 
 885  
                 LinkHandler.setBounds(lay, "visual", insX, insY, visW, visH, true, false);
 886  
                 LinkHandler.setBounds(lay, "container", 0, 0, parW, parH, true, false);
 887  
         }
 888  
 
 889  
         /** Returns the {@link net.miginfocom.layout.Grid.LinkedDimGroup} that has the {@link net.miginfocom.layout.Grid.CompWrap}
 890  
          * <code>cw</code>.
 891  
          * @param groupLists The lists to search in.
 892  
          * @param cw The component wrap to find.
 893  
          * @return The linked group or <code>null</code> if none had the component wrap.
 894  
          */
 895  
         private static LinkedDimGroup getGroupContaining(ArrayList<LinkedDimGroup>[] groupLists, CompWrap cw)
 896  
         {
 897  
                 for (ArrayList<LinkedDimGroup> groups : groupLists) {
 898  
                         for (int j = 0, jSz = groups.size(); j < jSz; j++) {
 899  
                                 ArrayList<CompWrap> cwList = groups.get(j)._compWraps;
 900  
                                 for (int k = 0, kSz = cwList.size(); k < kSz; k++) {
 901  
                                         if (cwList.get(k) == cw)
 902  
                                                 return groups.get(j);
 903  
                                 }
 904  
                         }
 905  
                 }
 906  
                 return null;
 907  
         }
 908  
 
 909  
         private boolean doAbsoluteCorrections(CompWrap cw, int[] bounds)
 910  
         {
 911  
                 boolean changed = false;
 912  
 
 913  
                 int[] stSz = getAbsoluteDimBounds(cw, bounds[2], true);
 914  
                 if (stSz != null)
 915  
                         cw.setDimBounds(stSz[0], stSz[1], true);
 916  
 
 917  
                 stSz = getAbsoluteDimBounds(cw, bounds[3], false);
 918  
                 if (stSz != null)
 919  
                         cw.setDimBounds(stSz[0], stSz[1], false);
 920  
 
 921  
                 // If there is a link id, store the new bounds.
 922  
                 if (linkTargetIDs != null)
 923  
                         changed = setLinkedBounds(cw.comp, cw.cc, cw.x, cw.y, cw.w, cw.h, false);
 924  
 
 925  
                 return changed;
 926  
         }
 927  
 
 928  
         private void adjustSizeForAbsolute(boolean isHor)
 929  
         {
 930  
                 int[] curSizes = isHor ? width : height;
 931  
 
 932  
                 Cell absCell = grid.get(null);
 933  
                 if (absCell == null || absCell.compWraps.size() == 0)
 934  
                         return;
 935  
 
 936  
                 ArrayList<CompWrap> cws = absCell.compWraps;
 937  
 
 938  
                 int maxEnd = 0;
 939  
                 for (int j = 0, cwSz = absCell.compWraps.size(); j < cwSz + 3; j++) {  // "Do Again" max absCell.compWraps.size() + 3 times.
 940  
                         boolean doAgain = false;
 941  
                         for (int i = 0; i < cwSz; i++) {
 942  
                                 CompWrap cw = cws.get(i);
 943  
                                 int[] stSz = getAbsoluteDimBounds(cw, 0, isHor);
 944  
                                 int end = stSz[0] + stSz[1];
 945  
                                 if (maxEnd < end)
 946  
                                         maxEnd = end;
 947  
 
 948  
                                 // If there is a link id, store the new bounds.
 949  
                                 if (linkTargetIDs != null)
 950  
                                         doAgain |= setLinkedBounds(cw.comp, cw.cc, stSz[0], stSz[0], stSz[1], stSz[1], false);
 951  
                         }
 952  
                         if (doAgain == false)
 953  
                                 break;
 954  
 
 955  
                         // We need to check this again since the coords may be smaller this round.
 956  
                         maxEnd = 0;
 957  
                         clearGroupLinkBounds();
 958  
                 }
 959  
 
 960  
                 maxEnd += LayoutUtil.getInsets(lc, isHor ? 3 : 2, !hasDocks()).getPixels(0, container, null);
 961  
 
 962  
                 if (curSizes[LayoutUtil.MIN] < maxEnd)
 963  
                         curSizes[LayoutUtil.MIN] = maxEnd;
 964  
                 if (curSizes[LayoutUtil.PREF] < maxEnd)
 965  
                         curSizes[LayoutUtil.PREF] = maxEnd;
 966  
         }
 967  
 
 968  
         private int[] getAbsoluteDimBounds(CompWrap cw, int refSize, boolean isHor)
 969  
         {
 970  
                 if (cw.cc.isExternal()) {
 971  
                         if (isHor) {
 972  
                                 return new int[] {cw.comp.getX(), cw.comp.getWidth()};
 973  
                         } else {
 974  
                                 return new int[] {cw.comp.getY(), cw.comp.getHeight()};
 975  
                         }
 976  
                 }
 977  
 
 978  
                 int[] plafPad = lc.isVisualPadding() ? cw.comp.getVisualPadding() : null;
 979  
                 UnitValue[] pad = cw.cc.getPadding();
 980  
 
 981  
                 // If no changes do not create a lot of objects
 982  
                 if (cw.pos == null && plafPad == null && pad == null)
 983  
                         return null;
 984  
 
 985  
                 // Set start
 986  
                 int st = isHor ? cw.x : cw.y;
 987  
                 int sz = isHor ? cw.w : cw.h;
 988  
 
 989  
                 // If absolute, use those coordinates instead.
 990  
                 if (cw.pos != null) {
 991  
                         UnitValue stUV = cw.pos != null ? cw.pos[isHor ? 0 : 1] : null;
 992  
                         UnitValue endUV = cw.pos != null ? cw.pos[isHor ? 2 : 3] : null;
 993  
 
 994  
                         int minSz = cw.getSize(LayoutUtil.MIN, isHor);
 995  
                         int maxSz = cw.getSize(LayoutUtil.MAX, isHor);
 996  
                         sz = Math.min(Math.max(cw.getSize(LayoutUtil.PREF, isHor), minSz), maxSz);
 997  
 
 998  
                         if (stUV != null) {
 999  
                                 st = stUV.getPixels(stUV.getUnit() == UnitValue.ALIGN ? sz : refSize, container, cw.comp);
 1000  
 
 1001  
                                 if (endUV != null)  // if (endUV == null && cw.cc.isBoundsIsGrid() == true)
 1002  
                                         sz = Math.min(Math.max((isHor ? (cw.x + cw.w) : (cw.y + cw.h)) - st, minSz), maxSz);
 1003  
                         }
 1004  
 
 1005  
                         if (endUV != null) {
 1006  
                                 if (stUV != null) {   // if (stUV != null || cw.cc.isBoundsIsGrid()) {
 1007  
                                         sz = Math.min(Math.max(endUV.getPixels(refSize, container, cw.comp) - st, minSz), maxSz);
 1008  
                                 } else {
 1009  
                                         st = endUV.getPixels(refSize, container, cw.comp) - sz;
 1010  
                                 }
 1011  
                         }
 1012  
                 }
 1013  
 
 1014  
                 // If constraint has padding -> correct the start/size
 1015  
                 if (pad != null) {
 1016  
                         UnitValue uv = pad[isHor ? 1 : 0];
 1017  
                         int p = uv != null ? uv.getPixels(refSize, container, cw.comp) : 0;
 1018  
                         st += p;
 1019  
                         uv = pad[isHor ? 3 : 2];
 1020  
                         sz += -p + (uv != null ? uv.getPixels(refSize, container, cw.comp) : 0);
 1021  
                 }
 1022  
 
 1023  
                 // If the plaf converter has padding -> correct the start/size
 1024  
                 if (plafPad != null) {
 1025  
                         int p = plafPad[isHor ? 1 : 0];
 1026  
                         st += p;
 1027  
                         sz += -p + (plafPad[isHor ? 3 : 2]);
 1028  
                 }
 1029  
 
 1030  
                 return new int[] {st, sz};
 1031  
         }
 1032  
 
 1033  
         private void layoutInOneDim(int refSize, UnitValue align, boolean isRows, Float[] defaultPushWeights)
 1034  
         {
 1035  
                 boolean fromEnd = !(isRows ? lc.isTopToBottom() : LayoutUtil.isLeftToRight(lc, container));
 1036  
                 DimConstraint[] primDCs = (isRows ? rowConstr : colConstr).getConstaints();
 1037  
                 FlowSizeSpec fss = isRows ? rowFlowSpecs : colFlowSpecs;
 1038  
                 ArrayList<LinkedDimGroup>[] rowCols = isRows ? rowGroupLists : colGroupLists;
 1039  
 
 1040  
                 int[] rowColSizes = LayoutUtil.calculateSerial(fss.sizes, fss.resConstsInclGaps, defaultPushWeights, LayoutUtil.PREF, refSize);
 1041  
 
 1042  
                 if (LayoutUtil.isDesignTime(container)) {
 1043  
                         TreeSet<Integer> indexes = isRows ? rowIndexes : colIndexes;
 1044  
                         int[] ixArr = new int[indexes.size()];
 1045  
                         int ix = 0;
 1046  
                         for (Integer i : indexes)
 1047  
                                 ixArr[ix++] = i;
 1048  
 
 1049  
                         putSizesAndIndexes(container.getComponent(), rowColSizes, ixArr, isRows);
 1050  
                 }
 1051  
 
 1052  
                 int curPos = align != null ? align.getPixels(refSize - LayoutUtil.sum(rowColSizes), container, null) : 0;
 1053  
 
 1054  
                 if (fromEnd)
 1055  
                         curPos = refSize - curPos;
 1056  
 
 1057  
                 for (int i = 0 ; i < rowCols.length; i++) {
 1058  
                         ArrayList<LinkedDimGroup> linkedGroups = rowCols[i];
 1059  
                         int scIx = i - (isRows ? dockOffY : dockOffX);
 1060  
 
 1061  
                         int bIx = i << 1;
 1062  
                         int bIx2 = bIx + 1;
 1063  
 
 1064  
                         curPos += (fromEnd ? -rowColSizes[bIx] : rowColSizes[bIx]);
 1065  
 
 1066  
                         DimConstraint primDC = scIx >= 0 ? primDCs[scIx >= primDCs.length ? primDCs.length - 1 : scIx] : DOCK_DIM_CONSTRAINT;
 1067  
 
 1068  
                         int rowSize = rowColSizes[bIx2];
 1069  
 
 1070  
                         for (LinkedDimGroup group : linkedGroups) {
 1071  
                                 int groupSize = rowSize;
 1072  
                                 if (group.span > 1)
 1073  
                                         groupSize = LayoutUtil.sum(rowColSizes, bIx2, Math.min((group.span << 1) - 1, rowColSizes.length - bIx2 - 1));
 1074  
 
 1075  
                                 group.layout(primDC, curPos, groupSize, group.span);
 1076  
                         }
 1077  
 
 1078  
                         curPos += (fromEnd ? -rowSize : rowSize);
 1079  
                 }
 1080  
         }
 1081  
 
 1082  
         private static void addToSizeGroup(HashMap<String, int[]> sizeGroups, String sizeGroup, int[] size)
 1083  
         {
 1084  
                 int[] sgSize = sizeGroups.get(sizeGroup);
 1085  
                 if (sgSize == null) {
 1086  
                         sizeGroups.put(sizeGroup, new int[] {size[LayoutUtil.MIN], size[LayoutUtil.PREF], size[LayoutUtil.MAX]});
 1087  
                 } else {
 1088  
                         sgSize[LayoutUtil.MIN] = Math.max(size[LayoutUtil.MIN], sgSize[LayoutUtil.MIN]);
 1089  
                         sgSize[LayoutUtil.PREF] = Math.max(size[LayoutUtil.PREF], sgSize[LayoutUtil.PREF]);
 1090  
                         sgSize[LayoutUtil.MAX] = Math.min(size[LayoutUtil.MAX], sgSize[LayoutUtil.MAX]);
 1091  
                 }
 1092  
         }
 1093  
 
 1094  
         private static HashMap<String, Integer> addToEndGroup(HashMap<String, Integer> endGroups, String endGroup, int end)
 1095  
         {
 1096  
                 if (endGroup != null) {
 1097  
                         if (endGroups == null)
 1098  
                                 endGroups = new HashMap<String, Integer>(2);
 1099  
 
 1100  
                         Integer oldEnd = endGroups.get(endGroup);
 1101  
                         if (oldEnd == null || end > oldEnd)
 1102  
                                 endGroups.put(endGroup, end);
 1103  
                 }
 1104  
                 return endGroups;
 1105  
         }
 1106  
 
 1107  
         /** Calculates Min, Preferred and Max size for the columns OR rows.
 1108  
          * @param isHor If it is the horizontal dimension to calculate.
 1109  
          * @return The sizes in a {@link net.miginfocom.layout.Grid.FlowSizeSpec}.
 1110  
          */
 1111  
         private FlowSizeSpec calcRowsOrColsSizes(boolean isHor)
 1112  
         {
 1113  
                 ArrayList<LinkedDimGroup>[] groupsLists = isHor ? colGroupLists : rowGroupLists;
 1114  
                 Float[] defPush = isHor ? pushXs : pushYs;
 1115  
                 int refSize = isHor ? container.getWidth() : container.getHeight();
 1116  
 
 1117  
                 BoundSize cSz = isHor ? lc.getWidth() : lc.getHeight();
 1118  
                 if (cSz.isUnset() == false)
 1119  
                         refSize = cSz.constrain(refSize, getParentSize(container, isHor), container);
 1120  
 
 1121  
                 DimConstraint[] primDCs = (isHor? colConstr : rowConstr).getConstaints();
 1122  
                 TreeSet<Integer> primIndexes = isHor ? colIndexes : rowIndexes;
 1123  
 
 1124  
                 int[][] rowColBoundSizes = new int[primIndexes.size()][];
 1125  
                 HashMap<String, int[]> sizeGroupMap = new HashMap<String, int[]>(2);
 1126  
                 DimConstraint[] allDCs = new DimConstraint[primIndexes.size()];
 1127  
 
 1128  
                 Iterator<Integer> primIt = primIndexes.iterator();
 1129  
                 for (int r = 0; r < rowColBoundSizes.length; r++) {
 1130  
                         int cellIx = primIt.next();
 1131  
                         int[] rowColSizes = new int[3];
 1132  
 
 1133  
                         if (cellIx >= -MAX_GRID && cellIx <= MAX_GRID) {  // If not dock cell
 1134  
                                 allDCs[r] = primDCs[cellIx >= primDCs.length ? primDCs.length - 1 : cellIx];
 1135  
                         } else {
 1136  
                                 allDCs[r] = DOCK_DIM_CONSTRAINT;
 1137  
                         }
 1138  
 
 1139  
                         ArrayList<LinkedDimGroup> groups = groupsLists[r];
 1140  
 
 1141  
                         int[] groupSizes = new int[] {
 1142  
                                         getTotalGroupsSizeParallel(groups, LayoutUtil.MIN, false),
 1143  
                                         getTotalGroupsSizeParallel(groups, LayoutUtil.PREF, false),
 1144  
                                         LayoutUtil.INF};
 1145  
 
 1146  
                         correctMinMax(groupSizes);
 1147  
                         BoundSize dimSize = allDCs[r].getSize();
 1148  
 
 1149  
                         for (int sType = LayoutUtil.MIN; sType <= LayoutUtil.MAX; sType++) {
 1150  
 
 1151  
                                 int rowColSize = groupSizes[sType];
 1152  
 
 1153  
                                 UnitValue uv = dimSize.getSize(sType);
 1154  
                                 if (uv != null) {
 1155  
                                         // If the size of the column is a link to some other size, use that instead
 1156  
                                         int unit = uv.getUnit();
 1157  
                                         if (unit == UnitValue.PREF_SIZE) {
 1158  
                                                 rowColSize = groupSizes[LayoutUtil.PREF];
 1159  
                                         } else if (unit == UnitValue.MIN_SIZE) {
 1160  
                                                 rowColSize = groupSizes[LayoutUtil.MIN];
 1161  
                                         } else if (unit == UnitValue.MAX_SIZE) {
 1162  
                                                 rowColSize = groupSizes[LayoutUtil.MAX];
 1163  
                                         } else {
 1164  
                                                 rowColSize = uv.getPixels(refSize, container, null);
 1165  
                                         }
 1166  
                                 } else if (cellIx >= -MAX_GRID && cellIx <= MAX_GRID && rowColSize == 0) {
 1167  
                                         rowColSize = LayoutUtil.isDesignTime(container) ? LayoutUtil.getDesignTimeEmptySize() : 0;    // Empty rows with no size set gets XX pixels if design time
 1168  
                                 }
 1169  
 
 1170  
                                 rowColSizes[sType] = rowColSize;
 1171  
                         }
 1172  
 
 1173  
                         correctMinMax(rowColSizes);
 1174  
                         addToSizeGroup(sizeGroupMap, allDCs[r].getSizeGroup(), rowColSizes);
 1175  
 
 1176  
                         rowColBoundSizes[r] = rowColSizes;
 1177  
                 }
 1178  
 
 1179  
                 // Set/equalize the size groups to same the values.
 1180  
                 if (sizeGroupMap.size() > 0) {
 1181  
                         for (int r = 0; r < rowColBoundSizes.length; r++) {
 1182  
                                 if (allDCs[r].getSizeGroup() != null)
 1183  
                                         rowColBoundSizes[r] = sizeGroupMap.get(allDCs[r].getSizeGroup());
 1184  
                         }
 1185  
                 }
 1186  
 
 1187  
                 // Add the gaps
 1188  
                 ResizeConstraint[] resConstrs = getRowResizeConstraints(allDCs);
 1189  
 
 1190  
                 boolean[] fillInPushGaps = new boolean[allDCs.length + 1];
 1191  
                 int[][] gapSizes = getRowGaps(allDCs, refSize, isHor, fillInPushGaps);
 1192  
 
 1193  
                 FlowSizeSpec fss = mergeSizesGapsAndResConstrs(resConstrs, fillInPushGaps, rowColBoundSizes, gapSizes);
 1194  
 
 1195  
                 // Spanning components are not handled yet. Check and adjust the multi-row min/pref they enforce.
 1196  
                 adjustMinPrefForSpanningComps(allDCs, defPush, fss, groupsLists);
 1197  
 
 1198  
                 return fss;
 1199  
         }
 1200  
 
 1201  
         private static int getParentSize(ComponentWrapper cw, boolean isHor)
 1202  
         {
 1203  
                 ComponentWrapper p = cw.getParent();
 1204  
                 return p != null ? (isHor ? cw.getWidth() : cw.getHeight()) : 0;
 1205  
         }
 1206  
 
 1207  
         private int[] getMinPrefMaxSumSize(boolean isHor)
 1208  
         {
 1209  
                 int[][] sizes = isHor ? colFlowSpecs.sizes : rowFlowSpecs.sizes;
 1210  
 
 1211  
                 int[] retSizes = new int[3];
 1212  
 
 1213  
                 BoundSize sz = isHor ? lc.getWidth() : lc.getHeight();
 1214  
 
 1215  
                 for (int i = 0; i < sizes.length; i++) {
 1216  
                         if (sizes[i] != null) {
 1217  
                                 int[] size = sizes[i];
 1218  
                                 for (int sType = LayoutUtil.MIN; sType <= LayoutUtil.MAX; sType++) {
 1219  
                                         if (sz.getSize(sType) != null) {
 1220  
                                                 if (i == 0)
 1221  
                                                         retSizes[sType] = sz.getSize(sType).getPixels(getParentSize(container, isHor), container, null);
 1222  
                                         } else {
 1223  
                                                 int s = size[sType];
 1224  
 
 1225  
                                                 if (s != LayoutUtil.NOT_SET) {
 1226  
                                                         if (sType == LayoutUtil.PREF) {
 1227  
                                                                 int bnd = size[LayoutUtil.MAX];
 1228  
                                                                 if (bnd != LayoutUtil.NOT_SET && bnd < s)
 1229  
                                                                         s = bnd;
 1230  
 
 1231  
                                                                 bnd = size[LayoutUtil.MIN];
 1232  
                                                                 if (bnd > s)    // Includes s == LayoutUtil.NOT_SET since < 0.
 1233  
                                                                         s = bnd;
 1234  
                                                         }
 1235  
 
 1236  
                                                         retSizes[sType] += s;   // MAX compensated below.
 1237  
                                                 }
 1238  
 
 1239  
                                                 // So that MAX is always correct.
 1240  
                                                 if (size[LayoutUtil.MAX] == LayoutUtil.NOT_SET || retSizes[LayoutUtil.MAX] > LayoutUtil.INF)
 1241  
                                                         retSizes[LayoutUtil.MAX] = LayoutUtil.INF;
 1242  
                                         }
 1243  
                                 }
 1244  
                         }
 1245  
                 }
 1246  
 
 1247  
                 correctMinMax(retSizes);
 1248  
 
 1249  
                 return retSizes;
 1250  
         }
 1251  
 
 1252  
         private static ResizeConstraint[] getRowResizeConstraints(DimConstraint[] specs)
 1253  
         {
 1254  
                 ResizeConstraint[] resConsts = new ResizeConstraint[specs.length];
 1255  
                 for (int i = 0; i < resConsts.length; i++)
 1256  
                         resConsts[i] = specs[i].resize;
 1257  
                 return resConsts;
 1258  
         }
 1259  
 
 1260  
         private static ResizeConstraint[] getComponentResizeConstraints(ArrayList<CompWrap> compWraps, boolean isHor)
 1261  
         {
 1262  
                 ResizeConstraint[] resConsts = new ResizeConstraint[compWraps.size()];
 1263  
                 for (int i = 0; i < resConsts.length; i++) {
 1264  
                         CC fc = compWraps.get(i).cc;
 1265  
                         resConsts[i] = fc.getDimConstraint(isHor).resize;
 1266  
 
 1267  
                         // Always grow docking components in the correct dimension.
 1268  
                         int dock = fc.getDockSide();
 1269  
                         if (isHor ? (dock == 0 || dock == 2) : (dock == 1 || dock == 3)) {
 1270  
                                 ResizeConstraint dc = resConsts[i];
 1271  
                                 resConsts[i] = new ResizeConstraint(dc.shrinkPrio, dc.shrink, dc.growPrio, ResizeConstraint.WEIGHT_100);
 1272  
                         }
 1273  
                 }
 1274  
                 return resConsts;
 1275  
         }
 1276  
 
 1277  
         private static boolean[] getComponentGapPush(ArrayList<CompWrap> compWraps, boolean isHor)
 1278  
         {
 1279  
                 // Make one element bigger and or the after gap with the next before gap.
 1280  
                 boolean[] barr = new boolean[compWraps.size() + 1];
 1281  
                 for (int i = 0; i < barr.length; i++) {
 1282  
 
 1283  
                         boolean push = i > 0 && compWraps.get(i - 1).isPushGap(isHor, false);
 1284  
 
 1285  
                         if (push == false && i < (barr.length - 1))
 1286  
                                 push = compWraps.get(i).isPushGap(isHor, true);
 1287  
 
 1288  
                         barr[i] = push;
 1289  
                 }
 1290  
                 return barr;
 1291  
         }
 1292  
 
 1293  
         /** Returns the row gaps in pixel sizes. One more than there are <code>specs</code> sent in.
 1294  
          * @param specs
 1295  
          * @param refSize
 1296  
          * @param isHor
 1297  
          * @param fillInPushGaps If the gaps are pushing. <b>NOTE!</b> this argument will be filled in and thus changed!
 1298  
          * @return The row gaps in pixel sizes. One more than there are <code>specs</code> sent in.
 1299  
          */
 1300  
         private int[][] getRowGaps(DimConstraint[] specs, int refSize, boolean isHor, boolean[] fillInPushGaps)
 1301  
         {
 1302  
                 BoundSize defGap = isHor ? lc.getGridGapX() : lc.getGridGapY();
 1303  
                 if (defGap == null)
 1304  
                         defGap = isHor ? PlatformDefaults.getGridGapX() : PlatformDefaults.getGridGapY();
 1305  
                 int[] defGapArr = defGap.getPixelSizes(refSize, container, null);
 1306  
 
 1307  
                 boolean defIns = !hasDocks();
 1308  
 
 1309  
                 UnitValue firstGap = LayoutUtil.getInsets(lc, isHor ? 1 : 0, defIns);
 1310  
                 UnitValue lastGap = LayoutUtil.getInsets(lc, isHor ? 3 : 2, defIns);
 1311  
 
 1312  
         int[][] retValues = new int[specs.length + 1][];
 1313  
 
 1314  
                 for (int i = 0, wgIx = 0; i < retValues.length; i++) {
 1315  
                 DimConstraint specBefore = i > 0 ? specs[i - 1] : null;
 1316  
                         DimConstraint specAfter = i < specs.length ? specs[i] : null;
 1317  
 
 1318  
                         // No gap if between docking components.
 1319  
                         boolean edgeBefore = (specBefore == DOCK_DIM_CONSTRAINT || specBefore == null);
 1320  
                         boolean edgeAfter = (specAfter == DOCK_DIM_CONSTRAINT || specAfter == null);
 1321  
                         if (edgeBefore && edgeAfter)
 1322  
                                 continue;
 1323  
 
 1324  
                         BoundSize wrapGapSize = (wrapGapMap == null || isHor == lc.isFlowX() ? null : wrapGapMap.get(Integer.valueOf(wgIx++)));
 1325  
 
 1326  
                         if (wrapGapSize == null) {
 1327  
 
 1328  
                                 int[] gapBefore = specBefore != null ? specBefore.getRowGaps(container, null, refSize, false) : null;
 1329  
                                 int[] gapAfter = specAfter != null ? specAfter.getRowGaps(container, null, refSize, true) : null;
 1330  
 
 1331  
                                 if (edgeBefore && gapAfter == null && firstGap != null) {
 1332  
 
 1333  
                                         int bef = firstGap.getPixels(refSize, container, null);
 1334  
                                         retValues[i] = new int[] {bef, bef, bef};
 1335  
 
 1336  
                                 } else if (edgeAfter && gapBefore == null && firstGap != null) {
 1337  
 
 1338  
                                         int aft = lastGap.getPixels(refSize, container, null);
 1339  
                                         retValues[i] = new int[] {aft, aft, aft};
 1340  
 
 1341  
                                 } else {
 1342  
                                         retValues[i] = gapAfter != gapBefore ? mergeSizes(gapAfter, gapBefore) : new int[] {defGapArr[0], defGapArr[1], defGapArr[2]};
 1343  
                                 }
 1344  
 
 1345  
                                 if (specBefore != null && specBefore.isGapAfterPush() || specAfter != null && specAfter.isGapBeforePush())
 1346  
                                         fillInPushGaps[i] = true;
 1347  
                         } else {
 1348  
 
 1349  
                                 if (wrapGapSize.isUnset()) {
 1350  
                                         retValues[i] = new int[] {defGapArr[0], defGapArr[1], defGapArr[2]};
 1351  
                                 } else {
 1352  
                                         retValues[i] = wrapGapSize.getPixelSizes(refSize, container, null);
 1353  
                                 }
 1354  
                                 fillInPushGaps[i] = wrapGapSize.getGapPush();
 1355  
                         }
 1356  
         }
 1357  
         return retValues;
 1358  
     }
 1359  
 
 1360  
         private static int[][] getGaps(ArrayList<CompWrap> compWraps, boolean isHor)
 1361  
         {
 1362  
                 int compCount = compWraps.size();
 1363  
         int[][] retValues = new int[compCount + 1][];
 1364  
 
 1365  
                 retValues[0] = compWraps.get(0).getGaps(isHor, true);
 1366  
         for (int i = 0; i < compCount; i++) {
 1367  
                 int[] gap1 = compWraps.get(i).getGaps(isHor, false);
 1368  
                 int[] gap2 = i < compCount - 1 ? compWraps.get(i + 1).getGaps(isHor, true) : null;
 1369  
 
 1370  
                         retValues[i + 1] = mergeSizes(gap1, gap2);
 1371  
         }
 1372  
 
 1373  
         return retValues;
 1374  
     }
 1375  
 
 1376  
         private boolean hasDocks()
 1377  
         {
 1378  
                 return (dockOffX > 0 || dockOffY > 0 || rowIndexes.last() > MAX_GRID || colIndexes.last() > MAX_GRID);
 1379  
         }
 1380  
 
 1381  
         /** Adjust min/pref size for columns(or rows) that has components that spans multiple columns (or rows).
 1382  
          * @param specs The specs for the columns or rows. Last index will be used if <code>count</code> is greater than this array's length.
 1383  
          * @param defPush The default grow weight if the specs does not have anyone that will grow. Comes from "push" in the CC.
 1384  
          * @param fss
 1385  
          * @param groupsLists
 1386  
          */
 1387  
         private void adjustMinPrefForSpanningComps(DimConstraint[] specs, Float[] defPush, FlowSizeSpec fss, ArrayList<LinkedDimGroup>[] groupsLists)
 1388  
         {
 1389  
                 for (int r = groupsLists.length - 1; r >= 0; r--) { // Since 3.7.3 Iterate from end to start. Will solve some multiple spanning components hard to solve problems.
 1390  
                         ArrayList<LinkedDimGroup> groups = groupsLists[r];
 1391  
 
 1392  
                         for (LinkedDimGroup group : groups) {
 1393  
                                 if (group.span == 1)
 1394  
                                         continue;
 1395  
 
 1396  
                                 int[] sizes = group.getMinPrefMax();
 1397  
                                 for (int s = LayoutUtil.MIN; s <= LayoutUtil.PREF; s++) {
 1398  
                                         int cSize = sizes[s];
 1399  
                                         if (cSize == LayoutUtil.NOT_SET)
 1400  
                                                 continue;
 1401  
 
 1402  
                                         int rowSize = 0;
 1403  
                                         int sIx = (r << 1) + 1;
 1404  
                                         int len = Math.min((group.span << 1), fss.sizes.length - sIx) - 1;
 1405  
                                         for (int j = sIx; j < sIx + len; j++) {
 1406  
                                                 int sz = fss.sizes[j][s];
 1407  
                                                 if (sz != LayoutUtil.NOT_SET)
 1408  
                                                         rowSize += sz;
 1409  
                                         }
 1410  
 
 1411  
                                         if (rowSize < cSize && len > 0) {
 1412  
                                                 for (int eagerness = 0, newRowSize = 0; eagerness < 4 && newRowSize < cSize; eagerness++)
 1413  
                                                         newRowSize = fss.expandSizes(specs, defPush, cSize, sIx, len, s, eagerness);
 1414  
                                         }
 1415  
                                 }
 1416  
                         }
 1417  
                 }
 1418  
         }
 1419  
 
 1420  
         /** For one dimension divide the component wraps into logical groups. One group for component wraps that share a common something,
 1421  
          * line the property to layout by base line.
 1422  
          * @param isRows If rows, and not columns, are to be divided.
 1423  
          * @return One <code>ArrayList<LinkedDimGroup></code> for every row/column.
 1424  
          */
 1425  
         private ArrayList<LinkedDimGroup>[] divideIntoLinkedGroups(boolean isRows)
 1426  
         {
 1427  
                 boolean fromEnd = !(isRows ? lc.isTopToBottom() : LayoutUtil.isLeftToRight(lc, container));
 1428  
                 TreeSet<Integer> primIndexes = isRows ? rowIndexes : colIndexes;
 1429  
                 TreeSet<Integer> secIndexes = isRows ? colIndexes : rowIndexes;
 1430  
                 DimConstraint[] primDCs = (isRows ? rowConstr : colConstr).getConstaints();
 1431  
 
 1432  
                 ArrayList<LinkedDimGroup>[] groupLists = new ArrayList[primIndexes.size()];
 1433  
 
 1434  
                 int gIx = 0;
 1435  
                 for (int i : primIndexes) {
 1436  
 
 1437  
                         DimConstraint dc;
 1438  
                         if (i >= -MAX_GRID && i <= MAX_GRID) {  // If not dock cell
 1439  
                                 dc = primDCs[i >= primDCs.length ? primDCs.length - 1 : i];
 1440  
                         } else {
 1441  
                                 dc = DOCK_DIM_CONSTRAINT;
 1442  
                         }
 1443  
 
 1444  
                         ArrayList<LinkedDimGroup> groupList = new ArrayList<LinkedDimGroup>(2);
 1445  
                         groupLists[gIx++] = groupList;
 1446  
 
 1447  
                         for (Integer ix : secIndexes) {
 1448  
                                 Cell cell = isRows ? getCell(i, ix) : getCell(ix, i);
 1449  
                                 if (cell == null || cell.compWraps.size() == 0)
 1450  
                                         continue;
 1451  
 
 1452  
                                 int span = (isRows ? cell.spany : cell.spanx);
 1453  
                                 if (span > 1)
 1454  
                                         span = convertSpanToSparseGrid(i, span, primIndexes);
 1455  
 
 1456  
                                 boolean isPar = (cell.flowx == isRows);
 1457  
 
 1458  
                                 if ((isPar == false && cell.compWraps.size() > 1) || span > 1) {
 1459  
 
 1460  
                                         int linkType = isPar ? LinkedDimGroup.TYPE_PARALLEL : LinkedDimGroup.TYPE_SERIAL;
 1461  
                                         LinkedDimGroup lg = new LinkedDimGroup("p," + ix, span, linkType, !isRows, fromEnd);
 1462  
                                         lg.setCompWraps(cell.compWraps);
 1463  
                                         groupList.add(lg);
 1464  
                                 } else {
 1465  
                                         for (int cwIx = 0; cwIx < cell.compWraps.size(); cwIx++) {
 1466  
                                                 CompWrap cw = cell.compWraps.get(cwIx);
 1467  
                                                 boolean rowBaselineAlign = (isRows && lc.isTopToBottom() && dc.getAlignOrDefault(!isRows) == UnitValue.BASELINE_IDENTITY); // Disable baseline for bottomToTop since I can not verify it working.
 1468  
                                                 boolean isBaseline = isRows && cw.isBaselineAlign(rowBaselineAlign);
 1469  
 
 1470  
                                                 String linkCtx = isBaseline ? "baseline" : null;
 1471  
 
 1472  
                                                 // Find a group with same link context and put it in that group.
 1473  
                                                 boolean foundList = false;
 1474  
                                                 for (int glIx = 0, lastGl = groupList.size() - 1; glIx <= lastGl; glIx++) {
 1475  
                                                         LinkedDimGroup group = groupList.get(glIx);
 1476  
                                                         if (group.linkCtx == linkCtx || linkCtx != null && linkCtx.equals(group.linkCtx)) {
 1477  
                                                                 group.addCompWrap(cw);
 1478  
                                                                 foundList = true;
 1479  
                                                                 break;
 1480  
                                                         }
 1481  
                                                 }
 1482  
 
 1483  
                                                 // If none found and at last add a new group.
 1484  
                                                 if (foundList == false) {
 1485  
                                                         int linkType = isBaseline ? LinkedDimGroup.TYPE_BASELINE : LinkedDimGroup.TYPE_PARALLEL;
 1486  
                                                         LinkedDimGroup lg = new LinkedDimGroup(linkCtx, 1, linkType, !isRows, fromEnd);
 1487  
                                                         lg.addCompWrap(cw);
 1488  
                                                         groupList.add(lg);
 1489  
                                                 }
 1490  
                                         }
 1491  
                                 }
 1492  
                         }
 1493  
                 }
 1494  
                 return groupLists;
 1495  
         }
 1496  
 
 1497  
         /** Spanning is specified in the uncompressed grid number. They can for instance be more than 60000 for the outer
 1498  
          * edge dock grid cells. When the grid is compressed and indexed after only the cells that area occupied the span
 1499  
          * is erratic. This method use the row/col indexes and corrects the span to be correct for the compressed grid.
 1500  
          * @param span The span un the uncompressed grid. <code>LayoutUtil.INF</code> will be interpreted to span the rest
 1501  
          * of the column/row excluding the surrounding docking components.
 1502  
          * @param indexes The indexes in the correct dimension.
 1503  
          * @return The converted span.
 1504  
          */
 1505  
         private static int convertSpanToSparseGrid(int curIx, int span, TreeSet<Integer> indexes)
 1506  
         {
 1507  
                 int lastIx = curIx + span;
 1508  
                 int retSpan = 1;
 1509  
 
 1510  
                 for (Integer ix : indexes) {
 1511  
                         if (ix <= curIx)
 1512  
                                 continue;   // We have not arrived to the correct index yet
 1513  
 
 1514  
                         if (ix >= lastIx)
 1515  
                                 break;
 1516  
 
 1517  
                         retSpan++;
 1518  
                 }
 1519  
                 return retSpan;
 1520  
         }
 1521  
 
 1522  
         private boolean isCellFree(int r, int c, ArrayList<int[]> occupiedRects)
 1523  
         {
 1524  
                 if (getCell(r, c) != null)
 1525  
                         return false;
 1526  
 
 1527  
                 for (int[] rect : occupiedRects) {
 1528  
                         if (rect[0] <= c && rect[1] <= r && rect[0] + rect[2] > c && rect[1] + rect[3] > r)
 1529  
                                 return false;
 1530  
                 }
 1531  
                 return true;
 1532  
         }
 1533  
 
 1534  
         private Cell getCell(int r, int c)
 1535  
         {
 1536  
                 return grid.get(Integer.valueOf((r << 16) + c));
 1537  
         }
 1538  
 
 1539  
         private void setCell(int r, int c, Cell cell)
 1540  
         {
 1541  
                 if (c < 0 || r < 0)
 1542  
                         throw new IllegalArgumentException("Cell position cannot be negative. row: " + r + ", col: " + c);
 1543  
 
 1544  
                 if (c > MAX_GRID || r > MAX_GRID)
 1545  
                         throw new IllegalArgumentException("Cell position out of bounds. Out of cells. row: " + r + ", col: " + c);
 1546  
 
 1547  
                 rowIndexes.add(r);
 1548  
                 colIndexes.add(c);
 1549  
 
 1550  
                 grid.put((r << 16) + c, cell);
 1551  
         }
 1552  
 
 1553  
         /** Adds a docking cell. That cell is outside the normal cell indexes.
 1554  
          * @param dockInsets The current dock insets. Will be updated!
 1555  
          * @param side top == 0, left == 1, bottom = 2, right = 3.
 1556  
          * @param cw The compwrap to put in a cell and add.
 1557  
          */
 1558  
         private void addDockingCell(int[] dockInsets, int side, CompWrap cw)
 1559  
         {
 1560  
                 int r, c, spanx = 1, spany = 1;
 1561  
                 switch (side) {
 1562  
                         case 0:
 1563  
                         case 2:
 1564  
                                 r = side == 0 ? dockInsets[0]++ : dockInsets[2]--;
 1565  
                                 c = dockInsets[1];
 1566  
                                 spanx = dockInsets[3] - dockInsets[1] + 1;  // The +1 is for cell 0.
 1567  
                                 colIndexes.add(dockInsets[3]); // Make sure there is a receiving cell
 1568  
                                 break;
 1569  
 
 1570  
                         case 1:
 1571  
                         case 3:
 1572  
                                 c = side == 1 ? dockInsets[1]++ : dockInsets[3]--;
 1573  
                                 r = dockInsets[0];
 1574  
                                 spany = dockInsets[2] - dockInsets[0] + 1;  // The +1 is for cell 0.
 1575  
                                 rowIndexes.add(dockInsets[2]); // Make sure there is a receiving cell
 1576  
                                 break;
 1577  
 
 1578  
                         default:
 1579  
                                 throw new IllegalArgumentException("Internal error 123.");
 1580  
                 }
 1581  
 
 1582  
                 rowIndexes.add(r);
 1583  
                 colIndexes.add(c);
 1584  
 
 1585  
                 grid.put((r << 16) + c, new Cell(cw, spanx, spany, spanx > 1));
 1586  
         }
 1587  
 
 1588  
         /** A simple representation of a cell in the grid. Contains a number of component wraps and if they span more than one cell.
 1589  
          */
 1590  
         private static class Cell
 1591  
         {
 1592  
                 private final int spanx, spany;
 1593  
                 private final boolean flowx;
 1594  
                 private final ArrayList<CompWrap> compWraps = new ArrayList<CompWrap>(1);
 1595  
 
 1596  
                 private boolean hasTagged = false;  // If one or more components have styles and need to be checked by the component sorter
 1597  
 
 1598  
                 private Cell(CompWrap cw)
 1599  
                 {
 1600  
                         this(cw, 1, 1, true);
 1601  
                 }
 1602  
 
 1603  
                 private Cell(int spanx, int spany, boolean flowx)
 1604  
                 {
 1605  
                         this(null, spanx, spany, flowx);
 1606  
                 }
 1607  
 
 1608  
                 private Cell(CompWrap cw, int spanx, int spany, boolean flowx)
 1609  
                 {
 1610  
                         if (cw != null)
 1611  
                                 compWraps.add(cw);
 1612  
                         this.spanx = spanx;
 1613  
                         this.spany = spany;
 1614  
                         this.flowx = flowx;
 1615  
                 }
 1616  
         }
 1617  
 
 1618  
         /** A number of component wraps that share a layout "something" <b>in one dimension</b>
 1619  
          */
 1620  
         private static class LinkedDimGroup
 1621  
         {
 1622  
                 private static final int TYPE_SERIAL = 0;
 1623  
                 private static final int TYPE_PARALLEL = 1;
 1624  
                 private static final int TYPE_BASELINE = 2;
 1625  
 
 1626  
                 private final String linkCtx;
 1627  
                 private final int span;
 1628  
                 private final int linkType;
 1629  
                 private final boolean isHor, fromEnd;
 1630  
 
 1631  
                 private ArrayList<CompWrap> _compWraps = new ArrayList<CompWrap>(4);
 1632  
 
 1633  
                 private int[] sizes = null;
 1634  
                 private int lStart = 0, lSize = 0;  // Currently mostly for debug painting
 1635  
 
 1636  
                 private LinkedDimGroup(String linkCtx, int span, int linkType, boolean isHor, boolean fromEnd)
 1637  
                 {
 1638  
                         this.linkCtx = linkCtx;
 1639  
                         this.span = span;
 1640  
                         this.linkType = linkType;
 1641  
                         this.isHor = isHor;
 1642  
                         this.fromEnd = fromEnd;
 1643  
                 }
 1644  
 
 1645  
                 private void addCompWrap(CompWrap cw)
 1646  
                 {
 1647  
                         _compWraps.add(cw);
 1648  
                         sizes = null;
 1649  
                 }
 1650  
 
 1651  
                 private void setCompWraps(ArrayList<CompWrap> cws)
 1652  
                 {
 1653  
                         if (_compWraps != cws) {
 1654  
                                 _compWraps = cws;
 1655  
                                 sizes = null;
 1656  
                         }
 1657  
                 }
 1658  
 
 1659  
                 private void layout(DimConstraint dc, int start, int size, int spanCount)
 1660  
                 {
 1661  
                         lStart = start;
 1662  
                         lSize = size;
 1663  
 
 1664  
                         if (_compWraps.size() == 0)
 1665  
                                 return;
 1666  
 
 1667  
                         ContainerWrapper parent = _compWraps.get(0).comp.getParent();
 1668  
                         if (linkType == TYPE_PARALLEL) {
 1669  
                                 layoutParallel(parent, _compWraps, dc, start, size, isHor, fromEnd);
 1670  
                         } else if (linkType == TYPE_BASELINE) {
 1671  
                                 layoutBaseline(parent, _compWraps, dc, start, size, LayoutUtil.PREF, spanCount);
 1672  
                         } else {
 1673  
                                 layoutSerial(parent, _compWraps, dc, start, size, isHor, spanCount, fromEnd);
 1674  
                         }
 1675  
                 }
 1676  
 
 1677  
                 /** Returns the min/pref/max sizes for this cell. Returned array <b>must not be altered</b>
 1678  
                  * @return A shared min/pref/max array of sizes. Always of length 3 and never <code>null</code>. Will always be of type STATIC and PIXEL.
 1679  
                  */
 1680  
                 private int[] getMinPrefMax()
 1681  
                 {
 1682  
                         if (sizes == null && _compWraps.size() > 0) {
 1683  
                                 sizes = new int[3];
 1684  
                                 for (int sType = LayoutUtil.MIN; sType <= LayoutUtil.PREF; sType++) {
 1685  
                                         if (linkType == TYPE_PARALLEL) {
 1686  
                                                 sizes[sType] = getTotalSizeParallel(_compWraps, sType, isHor);
 1687  
                                         } else if (linkType == TYPE_BASELINE) {
 1688  
                                                 int[] aboveBelow = getBaselineAboveBelow(_compWraps, sType, false);
 1689  
                                                 sizes[sType] = aboveBelow[0] + aboveBelow[1];
 1690  
                                         } else {
 1691  
                                                 sizes[sType] = getTotalSizeSerial(_compWraps, sType, isHor);
 1692  
                                         }
 1693  
                                 }
 1694  
                                 sizes[LayoutUtil.MAX] = LayoutUtil.INF;
 1695  
                         }
 1696  
                         return sizes;
 1697  
                 }
 1698  
         }
 1699  
 
 1700  
         /** Wraps a {@link java.awt.Component} together with its constraint. Caches a lot of information about the component so
 1701  
          * for instance not the preferred size has to be calculated more than once.
 1702  
          */
 1703  
         private final static class CompWrap
 1704  
         {
 1705  
                 private final ComponentWrapper comp;
 1706  
                 private final CC cc;
 1707  
                 private final UnitValue[] pos;
 1708  
                 private int[][] gaps; // [top,left(actually before),bottom,right(actually after)][min,pref,max]
 1709  
 
 1710  
                 private final int[] horSizes = new int[3];
 1711  
                 private final int[] verSizes = new int[3];
 1712  
 
 1713  
                 private int x = LayoutUtil.NOT_SET, y = LayoutUtil.NOT_SET, w = LayoutUtil.NOT_SET, h = LayoutUtil.NOT_SET;
 1714  
 
 1715  
                 private int forcedPushGaps = 0;   // 1 == before, 2 = after. Bitwise.
 1716  
 
 1717  
                 private CompWrap(ComponentWrapper c, CC cc, int eHideMode, UnitValue[] pos, BoundSize[] callbackSz)
 1718  
                 {
 1719  
                         this.comp = c;
 1720  
                         this.cc = cc;
 1721  
                         this.pos = pos;
 1722  
 
 1723  
                         if (eHideMode <= 0) {
 1724  
                                 BoundSize hBS = (callbackSz != null && callbackSz[0] != null) ? callbackSz[0] : cc.getHorizontal().getSize();
 1725  
                                 BoundSize vBS = (callbackSz != null && callbackSz[1] != null) ? callbackSz[1] : cc.getVertical().getSize();
 1726  
 
 1727  
                                 int wHint = -1, hHint = -1; // Added for v3.7
 1728  
                                 if (comp.getWidth() > 0 && comp.getHeight() > 0) {
 1729  
                                         hHint = comp.getHeight();
 1730  
                                         wHint = comp.getWidth();
 1731  
                                 }
 1732  
 
 1733  
                                 for (int i = LayoutUtil.MIN; i <= LayoutUtil.MAX; i++) {
 1734  
                                         horSizes[i] = getSize(hBS, i, true, hHint);
 1735  
                                         verSizes[i] = getSize(vBS, i, false, wHint > 0 ? wHint : horSizes[i]);
 1736  
                                 }
 1737  
 
 1738  
                                 correctMinMax(horSizes);
 1739  
                                 correctMinMax(verSizes);
 1740  
                         }
 1741  
 
 1742  
                         if (eHideMode > 1) {
 1743  
                                 gaps = new int[4][];
 1744  
                                 for (int i = 0; i < gaps.length; i++)
 1745  
                                         gaps[i] = new int[3];
 1746  
                         }
 1747  
                 }
 1748  
 
 1749  
                 private int getSize(BoundSize uvs, int sizeType, boolean isHor, int sizeHint)
 1750  
                 {
 1751  
                         if (uvs == null || uvs.getSize(sizeType) == null) {
 1752  
                                 switch(sizeType) {
 1753  
                                         case LayoutUtil.MIN:
 1754  
                                                 return isHor ? comp.getMinimumWidth(sizeHint) : comp.getMinimumHeight(sizeHint);
 1755  
                                         case LayoutUtil.PREF:
 1756  
                                                 return isHor ? comp.getPreferredWidth(sizeHint) : comp.getPreferredHeight(sizeHint);
 1757  
                                         default:
 1758  
                                                 return isHor ? comp.getMaximumWidth(sizeHint) : comp.getMaximumHeight(sizeHint);
 1759  
                                 }
 1760  
                         }
 1761  
 
 1762  
                         ContainerWrapper par = comp.getParent();
 1763  
                         return uvs.getSize(sizeType).getPixels(isHor ? par.getWidth() : par.getHeight(), par, comp);
 1764  
                 }
 1765  
 
 1766  
                 private void calcGaps(ComponentWrapper before, CC befCC, ComponentWrapper after, CC aftCC, String tag, boolean flowX, boolean isLTR)
 1767  
                 {
 1768  
                         ContainerWrapper par = comp.getParent();
 1769  
                         int parW = par.getWidth();
 1770  
                         int parH = par.getHeight();
 1771  
 
 1772  
                         BoundSize befGap = before != null ? (flowX ? befCC.getHorizontal() : befCC.getVertical()).getGapAfter() : null;
 1773  
                         BoundSize aftGap = after != null ? (flowX ? aftCC.getHorizontal() : aftCC.getVertical()).getGapBefore() : null;
 1774  
 
 1775  
                         mergeGapSizes(cc.getVertical().getComponentGaps(par, comp, befGap, (flowX ? null : before), tag, parH, 0, isLTR), false, true);
 1776  
                         mergeGapSizes(cc.getHorizontal().getComponentGaps(par, comp, befGap, (flowX ? before : null), tag, parW, 1, isLTR), true, true);
 1777  
                         mergeGapSizes(cc.getVertical().getComponentGaps(par, comp, aftGap, (flowX ? null : after), tag, parH, 2, isLTR), false, false);
 1778  
                         mergeGapSizes(cc.getHorizontal().getComponentGaps(par, comp, aftGap, (flowX ? after : null), tag, parW, 3, isLTR), true, false);
 1779  
                 }
 1780  
 
 1781  
                 private void setDimBounds(int start, int size, boolean isHor)
 1782  
                 {
 1783  
                         if (isHor) {
 1784  
                                 x = start;
 1785  
                                 w = size;
 1786  
                         } else {
 1787  
                                 y = start;
 1788  
                                 h = size;
 1789  
                         }
 1790  
                 }
 1791  
 
 1792  
                 private boolean isPushGap(boolean isHor, boolean isBefore)
 1793  
                 {
 1794  
                         if (isHor && ((isBefore ? 1 : 2) & forcedPushGaps) != 0)
 1795  
                                 return true;    // Forced
 1796  
 
 1797  
                         DimConstraint dc = cc.getDimConstraint(isHor);
 1798  
                         BoundSize s = isBefore ? dc.getGapBefore() : dc.getGapAfter();
 1799  
                         return s != null && s.getGapPush();
 1800  
                 }
 1801  
 
 1802  
                 /**
 1803  
                  * @return If the preferred size have changed because of the new bounds.
 1804  
                  */
 1805  
                 private boolean transferBounds(boolean checkPrefChange)
 1806  
                 {
 1807  
                         comp.setBounds(x, y, w, h);
 1808  
 
 1809  
                         if (checkPrefChange && w != horSizes[LayoutUtil.PREF]) {
 1810  
                                 BoundSize vSz = cc.getVertical().getSize();
 1811  
                                 if (vSz.getPreferred() == null) {
 1812  
                                         if (comp.getPreferredHeight(-1) != verSizes[LayoutUtil.PREF])
 1813  
                                                 return true;
 1814  
                                 }
 1815  
                         }
 1816  
                         return false;
 1817  
                 }
 1818  
 
 1819  
                 private void setSizes(int[] sizes, boolean isHor)
 1820  
                 {
 1821  
                         if (sizes == null)
 1822  
                                 return;
 1823  
 
 1824  
                         int[] s = isHor ? horSizes : verSizes;
 1825  
             s[LayoutUtil.MIN] = sizes[LayoutUtil.MIN];
 1826  
             s[LayoutUtil.PREF] = sizes[LayoutUtil.PREF];
 1827  
             s[LayoutUtil.MAX] = sizes[LayoutUtil.MAX];
 1828  
                 }
 1829  
 
 1830  
                 private void setGaps(int[] minPrefMax, int ix)
 1831  
                 {
 1832  
                         if (gaps == null)
 1833  
                                 gaps = new int[][] {null, null, null, null};
 1834  
 
 1835  
                         gaps[ix] = minPrefMax;
 1836  
                 }
 1837  
 
 1838  
                 private void mergeGapSizes(int[] sizes, boolean isHor, boolean isTL)
 1839  
                 {
 1840  
                         if (gaps == null)
 1841  
                                 gaps = new int[][] {null, null, null, null};
 1842  
 
 1843  
                         if (sizes == null)
 1844  
                                 return;
 1845  
 
 1846  
                         int gapIX = getGapIx(isHor, isTL);
 1847  
                         int[] oldGaps = gaps[gapIX];
 1848  
                         if (oldGaps == null) {
 1849  
                                 oldGaps = new int[] {0, 0, LayoutUtil.INF};
 1850  
                                 gaps[gapIX] = oldGaps;
 1851  
                         }
 1852  
 
 1853  
                         oldGaps[LayoutUtil.MIN] = Math.max(sizes[LayoutUtil.MIN], oldGaps[LayoutUtil.MIN]);
 1854  
                         oldGaps[LayoutUtil.PREF] = Math.max(sizes[LayoutUtil.PREF], oldGaps[LayoutUtil.PREF]);
 1855  
                         oldGaps[LayoutUtil.MAX] = Math.min(sizes[LayoutUtil.MAX], oldGaps[LayoutUtil.MAX]);
 1856  
                 }
 1857  
 
 1858  
                 private int getGapIx(boolean isHor, boolean isTL)
 1859  
                 {
 1860  
                         return isHor ? (isTL ? 1 : 3) : (isTL ? 0 : 2);
 1861  
                 }
 1862  
 
 1863  
                 private int getSizeInclGaps(int sizeType, boolean isHor)
 1864  
                 {
 1865  
                         return filter(sizeType, getGapBefore(sizeType, isHor) + getSize(sizeType, isHor) + getGapAfter(sizeType, isHor));
 1866  
                 }
 1867  
 
 1868  
                 private int getSize(int sizeType, boolean isHor)
 1869  
                 {
 1870  
                         return filter(sizeType, isHor ? horSizes[sizeType] : verSizes[sizeType]);
 1871  
                 }
 1872  
 
 1873  
                 private int getGapBefore(int sizeType, boolean isHor)
 1874  
                 {
 1875  
                         int[] gaps = getGaps(isHor, true);
 1876  
                         return gaps != null ? filter(sizeType, gaps[sizeType]) : 0;
 1877  
                 }
 1878  
 
 1879  
                 private int getGapAfter(int sizeType, boolean isHor)
 1880  
                 {
 1881  
                         int[] gaps = getGaps(isHor, false);
 1882  
                         return gaps != null ? filter(sizeType, gaps[sizeType]) : 0;
 1883  
                 }
 1884  
 
 1885  
                 private int[] getGaps(boolean isHor, boolean isTL)
 1886  
                 {
 1887  
                         return gaps[getGapIx(isHor, isTL)];
 1888  
                 }
 1889  
 
 1890  
                 private int filter(int sizeType, int size)
 1891  
                 {
 1892  
                         if (size == LayoutUtil.NOT_SET)
 1893  
                                 return sizeType != LayoutUtil.MAX ? 0 : LayoutUtil.INF;
 1894  
                         return constrainSize(size);
 1895  
                 }
 1896  
 
 1897  
                 private boolean isBaselineAlign(boolean defValue)
 1898  
                 {
 1899  
                         Float g = cc.getVertical().getGrow();
 1900  
                         if (g != null && g.intValue() != 0)
 1901  
                                 return false;
 1902  
 
 1903  
                         UnitValue al = cc.getVertical().getAlign();
 1904  
                         return (al != null ? al == UnitValue.BASELINE_IDENTITY : defValue) && comp.hasBaseline();
 1905  
                 }
 1906  
 
 1907  
                 private int getBaseline(int sizeType)
 1908  
                 {
 1909  
                         return comp.getBaseline(getSize(sizeType, true), getSize(sizeType, false));
 1910  
                 }
 1911  
         }
 1912  
 
 1913  
         //***************************************************************************************
 1914  
         //* Helper Methods
 1915  
         //***************************************************************************************
 1916  
 
 1917  
         private static void layoutBaseline(ContainerWrapper parent, ArrayList<CompWrap> compWraps, DimConstraint dc, int start, int size, int sizeType, int spanCount)
 1918  
         {
 1919  
                 int[] aboveBelow = getBaselineAboveBelow(compWraps, sizeType, true);
 1920  
                 int blRowSize = aboveBelow[0] + aboveBelow[1];
 1921  
 
 1922  
                 CC cc = compWraps.get(0).cc;
 1923  
 
 1924  
                 // Align for the whole baseline component array
 1925  
                 UnitValue align = cc.getVertical().getAlign();
 1926  
                 if (spanCount == 1 && align == null)
 1927  
                         align = dc.getAlignOrDefault(false);
 1928  
                 if (align == UnitValue.BASELINE_IDENTITY)
 1929  
                         align = UnitValue.CENTER;
 1930  
 
 1931  
                 int offset = start + aboveBelow[0] + (align != null ? Math.max(0, align.getPixels(size - blRowSize, parent, null)) : 0);
 1932  
                 for (int i = 0, iSz = compWraps.size(); i < iSz; i++) {
 1933  
                         CompWrap cw = compWraps.get(i);
 1934  
                         cw.y += offset;
 1935  
                         if (cw.y + cw.h > start + size)
 1936  
                                 cw.h = start + size - cw.y;
 1937  
                 }
 1938  
         }
 1939  
 
 1940  
         private static void layoutSerial(ContainerWrapper parent, ArrayList<CompWrap> compWraps, DimConstraint dc, int start, int size, boolean isHor, int spanCount, boolean fromEnd)
 1941  
         {
 1942  
                 FlowSizeSpec fss = mergeSizesGapsAndResConstrs(
 1943  
                                 getComponentResizeConstraints(compWraps, isHor),
 1944  
                         getComponentGapPush(compWraps, isHor),
 1945  
                                 getComponentSizes(compWraps, isHor),
 1946  
                                 getGaps(compWraps, isHor));
 1947  
 
 1948  
                 Float[] pushW = dc.isFill() ? GROW_100 : null;
 1949  
                 int[] sizes = LayoutUtil.calculateSerial(fss.sizes, fss.resConstsInclGaps, pushW, LayoutUtil.PREF, size);
 1950  
                 setCompWrapBounds(parent, sizes, compWraps, dc.getAlignOrDefault(isHor),  start, size, isHor, fromEnd);
 1951  
         }
 1952  
 
 1953  
         private static void setCompWrapBounds(ContainerWrapper parent, int[] allSizes, ArrayList<CompWrap> compWraps, UnitValue rowAlign,  int start, int size, boolean isHor, boolean fromEnd)
 1954  
         {
 1955  
                 int totSize = LayoutUtil.sum(allSizes);
 1956  
                 CC cc = compWraps.get(0).cc;
 1957  
                 UnitValue align = correctAlign(cc, rowAlign, isHor, fromEnd);
 1958  
 
 1959  
                 int cSt = start;
 1960  
                 int slack = size - totSize;
 1961  
                 if (slack > 0 && align != null) {
 1962  
                         int al = Math.min(slack, Math.max(0, align.getPixels(slack, parent, null)));
 1963  
                         cSt += (fromEnd ? -al : al);
 1964  
                 }
 1965  
 
 1966  
                 for (int i = 0, bIx = 0, iSz = compWraps.size(); i < iSz; i++) {
 1967  
                         CompWrap cw = compWraps.get(i);
 1968  
                         if (fromEnd ) {
 1969  
                                 cSt -= allSizes[bIx++];
 1970  
                                 cw.setDimBounds(cSt - allSizes[bIx], allSizes[bIx], isHor);
 1971  
                                 cSt -= allSizes[bIx++];
 1972  
                         } else {
 1973  
                                 cSt += allSizes[bIx++];
 1974  
                                 cw.setDimBounds(cSt, allSizes[bIx], isHor);
 1975  
                                 cSt += allSizes[bIx++];
 1976  
                         }
 1977  
                 }
 1978  
         }
 1979  
 
 1980  
         private static void layoutParallel(ContainerWrapper parent, ArrayList<CompWrap> compWraps, DimConstraint dc, int start, int size, boolean isHor, boolean fromEnd)
 1981  
         {
 1982  
                 int[][] sizes = new int[compWraps.size()][];    // [compIx][gapBef,compSize,gapAft]
 1983  
 
 1984  
                 for (int i = 0; i < sizes.length; i++) {
 1985  
                         CompWrap cw = compWraps.get(i);
 1986  
 
 1987  
                         DimConstraint cDc = cw.cc.getDimConstraint(isHor);
 1988  
 
 1989  
                         ResizeConstraint[] resConstr = new ResizeConstraint[] {
 1990  
                                         cw.isPushGap(isHor, true) ? GAP_RC_CONST_PUSH : GAP_RC_CONST,
 1991  
                                         cDc.resize,
 1992  
                                         cw.isPushGap(isHor, false) ? GAP_RC_CONST_PUSH : GAP_RC_CONST,
 1993  
                         };
 1994  
 
 1995  
                         int[][] sz = new int[][] {
 1996  
                                 cw.getGaps(isHor, true), (isHor ? cw.horSizes : cw.verSizes), cw.getGaps(isHor, false)
 1997  
                         };
 1998  
 
 1999  
                         Float[] pushW = dc.isFill() ? GROW_100 : null;
 2000  
 
 2001  
                         sizes[i] = LayoutUtil.calculateSerial(sz, resConstr, pushW, LayoutUtil.PREF, size);
 2002  
                 }
 2003  
 
 2004  
                 UnitValue rowAlign = dc.getAlignOrDefault(isHor);
 2005  
                 setCompWrapBounds(parent, sizes, compWraps, rowAlign, start, size, isHor, fromEnd);
 2006  
         }
 2007  
 
 2008  
         private static void setCompWrapBounds(ContainerWrapper parent, int[][] sizes, ArrayList<CompWrap> compWraps, UnitValue rowAlign,  int start, int size, boolean isHor, boolean fromEnd)
 2009  
         {
 2010  
                 for (int i = 0; i < sizes.length; i++) {
 2011  
                         CompWrap cw = compWraps.get(i);
 2012  
 
 2013  
                         UnitValue align = correctAlign(cw.cc, rowAlign, isHor, fromEnd);
 2014  
 
 2015  
                         int[] cSizes = sizes[i];
 2016  
                         int gapBef = cSizes[0];
 2017  
                         int cSize = cSizes[1];  // No Math.min(size, cSizes[1]) here!
 2018  
                         int gapAft = cSizes[2];
 2019  
 
 2020  
                         int cSt = fromEnd ? start - gapBef : start + gapBef;
 2021  
                         int slack = size - cSize - gapBef - gapAft;
 2022  
                         if (slack > 0 && align != null) {
 2023  
                                 int al = Math.min(slack, Math.max(0, align.getPixels(slack, parent, null)));
 2024  
                                 cSt += (fromEnd ? -al : al);
 2025  
                         }
 2026  
 
 2027  
                         cw.setDimBounds(fromEnd ? cSt - cSize : cSt, cSize, isHor);
 2028  
                 }
 2029  
         }
 2030  
 
 2031  
         private static UnitValue correctAlign(CC cc, UnitValue rowAlign, boolean isHor, boolean fromEnd)
 2032  
         {
 2033  
                 UnitValue align = (isHor ? cc.getHorizontal() : cc.getVertical()).getAlign();
 2034  
                 if (align == null)
 2035  
                         align = rowAlign;
 2036  
                 if (align == UnitValue.BASELINE_IDENTITY)
 2037  
                         align = UnitValue.CENTER;
 2038  
 
 2039  
                 if (fromEnd) {
 2040  
                         if (align == UnitValue.LEFT)
 2041  
                                 align = UnitValue.RIGHT;
 2042  
                         else if (align == UnitValue.RIGHT)
 2043  
                                 align = UnitValue.LEFT;
 2044  
                 }
 2045  
                 return align;
 2046  
         }
 2047  
 
 2048  
         private static int[] getBaselineAboveBelow(ArrayList<CompWrap> compWraps, int sType, boolean centerBaseline)
 2049  
         {
 2050  
                 int maxAbove = Short.MIN_VALUE;
 2051  
                 int maxBelow = Short.MIN_VALUE;
 2052  
                 for (int i = 0, iSz = compWraps.size(); i < iSz; i++) {
 2053  
                         CompWrap cw = compWraps.get(i);
 2054  
 
 2055  
                         int height = cw.getSize(sType, false);
 2056  
                         if (height >= LayoutUtil.INF)
 2057  
                                 return new int[] {LayoutUtil.INF / 2, LayoutUtil.INF / 2};
 2058  
 
 2059  
                         int baseline = cw.getBaseline(sType);
 2060  
                         int above = baseline + cw.getGapBefore(sType, false);
 2061  
                         maxAbove = Math.max(above, maxAbove);
 2062  
                         maxBelow = Math.max(height - baseline + cw.getGapAfter(sType, false), maxBelow);
 2063  
 
 2064  
                         if (centerBaseline)
 2065  
                                 cw.setDimBounds(-baseline, height, false);
 2066  
                 }
 2067  
                 return new int[] {maxAbove, maxBelow};
 2068  
         }
 2069  
 
 2070  
         private static int getTotalSizeParallel(ArrayList<CompWrap> compWraps, int sType, boolean isHor)
 2071  
         {
 2072  
                 int size = sType == LayoutUtil.MAX ? LayoutUtil.INF : 0;
 2073  
 
 2074  
                 for (int i = 0, iSz = compWraps.size(); i < iSz; i++) {
 2075  
                         CompWrap cw = compWraps.get(i);
 2076  
                         int cwSize = cw.getSizeInclGaps(sType, isHor);
 2077  
                         if (cwSize >= LayoutUtil.INF)
 2078  
                                 return LayoutUtil.INF;
 2079  
 
 2080  
                         if (sType == LayoutUtil.MAX ? cwSize < size : cwSize > size)
 2081  
                         size = cwSize;
 2082  
                 }
 2083  
                 return constrainSize(size);
 2084  
         }
 2085  
 
 2086  
         private static int getTotalSizeSerial(ArrayList<CompWrap> compWraps, int sType, boolean isHor)
 2087  
         {
 2088  
                 int totSize = 0;
 2089  
                 for (int i = 0, iSz = compWraps.size(), lastGapAfter = 0; i < iSz; i++) {
 2090  
                         CompWrap wrap = compWraps.get(i);
 2091  
                         int gapBef = wrap.getGapBefore(sType, isHor);
 2092  
                         if (gapBef > lastGapAfter)
 2093  
                                 totSize += gapBef - lastGapAfter;
 2094  
 
 2095  
                         totSize += wrap.getSize(sType, isHor);
 2096  
                         totSize += (lastGapAfter = wrap.getGapAfter(sType, isHor));
 2097  
 
 2098  
                         if (totSize >= LayoutUtil.INF)
 2099  
                                 return LayoutUtil.INF;
 2100  
                 }
 2101  
                 return constrainSize(totSize);
 2102  
         }
 2103  
 
 2104  
         private static int getTotalGroupsSizeParallel(ArrayList<LinkedDimGroup> groups, int sType, boolean countSpanning)
 2105  
         {
 2106  
                 int size = sType == LayoutUtil.MAX ? LayoutUtil.INF : 0;
 2107  
                 for (int i = 0, iSz = groups.size(); i < iSz; i++) {
 2108  
                         LinkedDimGroup group = groups.get(i);
 2109  
                         if (countSpanning || group.span == 1) {
 2110  
                                 int grpSize = group.getMinPrefMax()[sType];
 2111  
                                 if (grpSize >= LayoutUtil.INF)
 2112  
                                         return LayoutUtil.INF;
 2113  
 
 2114  
                                 if (sType == LayoutUtil.MAX ? grpSize < size : grpSize > size)
 2115  
                                 size = grpSize;
 2116  
                         }
 2117  
                 }
 2118  
                 return constrainSize(size);
 2119  
         }
 2120  
 
 2121  
         /**
 2122  
          * @param compWraps
 2123  
          * @param isHor
 2124  
          * @return Might contain LayoutUtil.NOT_SET
 2125  
          */
 2126  
         private static int[][] getComponentSizes(ArrayList<CompWrap> compWraps, boolean isHor)
 2127  
         {
 2128  
                 int[][] compSizes = new int[compWraps.size()][];
 2129  
                 for (int i = 0; i < compSizes.length; i++) {
 2130  
                         CompWrap cw = compWraps.get(i);
 2131  
                         compSizes[i] = isHor ? cw.horSizes : cw.verSizes;
 2132  
                 }
 2133  
                 return compSizes;
 2134  
         }
 2135  
 
 2136  
         /** Merges sizes and gaps together with Resize Constraints. For gaps {@link #GAP_RC_CONST} is used.
 2137  
          * @param resConstr One resize constriant for every row/component. Can be lesser in length and the last element should be used for missing elements.
 2138  
          * @param gapPush If the corresponding gap should be considered pushing and thus want to take free space if left over. Should be one more than resConstrs!
 2139  
          * @param minPrefMaxSizes The sizes (min/pref/max) for every row/component.
 2140  
          * @param gapSizes The gaps before and after each row/component packed in one double sized array.
 2141  
          * @return A holder for the merged values.
 2142  
          */
 2143  
         private static FlowSizeSpec mergeSizesGapsAndResConstrs(ResizeConstraint[] resConstr, boolean[] gapPush, int[][] minPrefMaxSizes, int[][] gapSizes)
 2144  
         {
 2145  
                 int[][] sizes = new int[(minPrefMaxSizes.length << 1) + 1][];  // Make room for gaps around.
 2146  
                 ResizeConstraint[] resConstsInclGaps = new ResizeConstraint[sizes.length];
 2147  
 
 2148  
                 sizes[0] = gapSizes[0];
 2149  
                 for (int i = 0, crIx = 1; i < minPrefMaxSizes.length; i++, crIx += 2) {
 2150  
 
 2151  
                         // Component bounds and constraints
 2152  
                         resConstsInclGaps[crIx] = resConstr[i];
 2153  
                         sizes[crIx] = minPrefMaxSizes[i];
 2154  
 
 2155  
                         sizes[crIx + 1] = gapSizes[i + 1];
 2156  
 
 2157  
                         if (sizes[crIx - 1] != null)
 2158  
                                 resConstsInclGaps[crIx - 1] = gapPush[i < gapPush.length ? i : gapPush.length - 1] ? GAP_RC_CONST_PUSH : GAP_RC_CONST;
 2159  
 
 2160  
                         if (i == (minPrefMaxSizes.length - 1) && sizes[crIx + 1] != null)
 2161  
                                 resConstsInclGaps[crIx + 1] = gapPush[(i + 1) < gapPush.length ? (i + 1) : gapPush.length - 1] ? GAP_RC_CONST_PUSH : GAP_RC_CONST;
 2162  
                 }
 2163  
 
 2164  
                 // Check for null and set it to 0, 0, 0.
 2165  
                 for (int i = 0; i < sizes.length; i++) {
 2166  
                         if (sizes[i] == null)
 2167  
                                 sizes[i] = new int[3];
 2168  
                 }
 2169  
 
 2170  
                 return new FlowSizeSpec(sizes, resConstsInclGaps);
 2171  
         }
 2172  
 
 2173  
         private static int[] mergeSizes(int[] oldValues, int[] newValues)
 2174  
         {
 2175  
                 if (oldValues == null)
 2176  
                         return newValues;
 2177  
 
 2178  
                 if (newValues == null)
 2179  
                         return oldValues;
 2180  
 
 2181  
                 int[] ret = new int[oldValues.length];
 2182  
                 for (int i = 0; i < ret.length; i++)
 2183  
                         ret[i] = mergeSizes(oldValues[i], newValues[i], true);
 2184  
 
 2185  
                 return ret;
 2186  
         }
 2187  
 
 2188  
         private static int mergeSizes(int oldValue, int newValue, boolean toMax)
 2189  
         {
 2190  
                 if (oldValue == LayoutUtil.NOT_SET || oldValue == newValue)
 2191  
                         return newValue;
 2192  
 
 2193  
                 if (newValue == LayoutUtil.NOT_SET)
 2194  
                         return oldValue;
 2195  
 
 2196  
                 return toMax != oldValue > newValue ? newValue : oldValue;
 2197  
         }
 2198  
 
 2199  
         private static int constrainSize(int s)
 2200  
         {
 2201  
                 return s > 0 ? (s < LayoutUtil.INF ? s : LayoutUtil.INF) : 0;
 2202  
         }
 2203  
 
 2204  
         private static void correctMinMax(int s[])
 2205  
         {
 2206  
                 if (s[LayoutUtil.MIN] > s[LayoutUtil.MAX])
 2207  
                         s[LayoutUtil.MIN] = s[LayoutUtil.MAX];  // Since MAX is almost always explicitly set use that
 2208  
 
 2209  
                 if (s[LayoutUtil.PREF] < s[LayoutUtil.MIN])
 2210  
                         s[LayoutUtil.PREF] = s[LayoutUtil.MIN];
 2211  
 
 2212  
                 if (s[LayoutUtil.PREF] > s[LayoutUtil.MAX])
 2213  
                         s[LayoutUtil.PREF] = s[LayoutUtil.MAX];
 2214  
         }
 2215  
 
 2216  
         private static final class FlowSizeSpec
 2217  
         {
 2218  
                 private final int[][] sizes;  // [row/col index][min, pref, max]
 2219  
                 private final ResizeConstraint[] resConstsInclGaps;  // [row/col index]
 2220  
 
 2221  
                 private FlowSizeSpec(int[][] sizes, ResizeConstraint[] resConstsInclGaps)
 2222  
                 {
 2223  
                         this.sizes = sizes;
 2224  
                         this.resConstsInclGaps = resConstsInclGaps;
 2225  
                 }
 2226  
 
 2227  
                 /**
 2228  
                  * @param specs The specs for the columns or rows. Last index will be used of <code>fromIx + len</code> is greater than this array's length.
 2229  
                  * @param targetSize The size to try to meet.
 2230  
                  * @param defGrow The default grow weight if the specs does not have anyone that will grow. Comes from "push" in the CC.
 2231  
                  * @param fromIx
 2232  
                  * @param len
 2233  
                  * @param sizeType
 2234  
                  * @param eagerness How eager the algorithm should be to try to expand the sizes.
 2235  
                  * <ul>
 2236  
                  * <li>0 - Grow only rows/columns which have the <code>sizeType</code> set to be the containing components AND which has a grow weight &gt; 0.
 2237  
                  * <li>1 - Grow only rows/columns which have the <code>sizeType</code> set to be the containing components AND which has a grow weight &gt; 0 OR unspecified.
 2238  
                  * <li>2 - Grow all rows/columns that have a grow weight &gt; 0.
 2239  
                  * <li>3 - Grow all rows/columns that have a grow weight &gt; 0 OR unspecified.
 2240  
                  * </ul>
 2241  
                  * @return The new size.
 2242  
                  */
 2243  
                 private int expandSizes(DimConstraint[] specs, Float[] defGrow, int targetSize, int fromIx, int len, int sizeType, int eagerness)
 2244  
                 {
 2245  
                         ResizeConstraint[] resConstr = new ResizeConstraint[len];
 2246  
                         int[][] sizesToExpand = new int[len][];
 2247  
                         for (int i = 0; i < len; i++) {
 2248  
                                 int[] minPrefMax = sizes[i + fromIx];
 2249  
                                 sizesToExpand[i] = new int[] {minPrefMax[sizeType], minPrefMax[LayoutUtil.PREF], minPrefMax[LayoutUtil.MAX]};
 2250  
 
 2251  
                                 if (eagerness <= 1 && i % 2 == 0) { // (i % 2 == 0) means only odd indexes, which is only rows/col indexes and not gaps.
 2252  
                                         int cIx = (i + fromIx - 1) >> 1;
 2253  
                                         DimConstraint spec = (DimConstraint) LayoutUtil.getIndexSafe(specs, cIx);
 2254  
 
 2255  
                                         BoundSize sz = spec.getSize();
 2256  
                                         if (    (sizeType == LayoutUtil.MIN && sz.getMin() != null && sz.getMin().getUnit() != UnitValue.MIN_SIZE) ||
 2257  
                                                 (sizeType == LayoutUtil.PREF && sz.getPreferred() != null && sz.getPreferred().getUnit() != UnitValue.PREF_SIZE)) {
 2258  
                                                 continue;
 2259  
                                         }
 2260  
                                 }
 2261  
                                 resConstr[i] = (ResizeConstraint) LayoutUtil.getIndexSafe(resConstsInclGaps, i + fromIx);
 2262  
                         }
 2263  
 
 2264  
                         Float[] growW = (eagerness == 1 || eagerness == 3) ? extractSubArray(specs, defGrow, fromIx, len): null;
 2265  
                         int[] newSizes = LayoutUtil.calculateSerial(sizesToExpand, resConstr, growW, LayoutUtil.PREF, targetSize);
 2266  
                         int newSize = 0;
 2267  
 
 2268  
                         for (int i = 0; i < len; i++) {
 2269  
                                 int s = newSizes[i];
 2270  
                                 sizes[i + fromIx][sizeType] = s;
 2271  
                                 newSize += s;
 2272  
                         }
 2273  
                         return newSize;
 2274  
                 }
 2275  
         }
 2276  
 
 2277  
         private static Float[] extractSubArray(DimConstraint[] specs, Float[] arr, int ix, int len)
 2278  
         {
 2279  
                 if (arr == null || arr.length < ix + len) {
 2280  
                         Float[] growLastArr = new Float[len];
 2281  
 
 2282  
                         // Handle a group where some rows (first one/few and/or last one/few) are docks.
 2283  
                         for (int i = ix + len - 1; i >= 0; i -= 2) {
 2284  
                                 int specIx = (i >> 1);
 2285  
                                 if (specs[specIx] != DOCK_DIM_CONSTRAINT) {
 2286  
                                         growLastArr[i - ix] = ResizeConstraint.WEIGHT_100;
 2287  
                                         return growLastArr;
 2288  
                                 }
 2289  
                         }
 2290  
                         return growLastArr;
 2291  
                 }
 2292  
 
 2293  
                 Float[] newArr = new Float[len];
 2294  
                 for (int i = 0; i < len; i++)
 2295  
                         newArr[i] = arr[ix + i];
 2296  
                 return newArr;
 2297  
         }
 2298  
 
 2299  
         private static WeakHashMap[] PARENT_ROWCOL_SIZES_MAP = null;
 2300  
         private static synchronized void putSizesAndIndexes(Object parComp, int[] sizes, int[] ixArr, boolean isRows)
 2301  
         {
 2302  
                 if (PARENT_ROWCOL_SIZES_MAP == null)    // Lazy since only if designing in IDEs
 2303  
                         PARENT_ROWCOL_SIZES_MAP = new WeakHashMap[] {new WeakHashMap(4), new WeakHashMap(4)};
 2304  
 
 2305  
                 PARENT_ROWCOL_SIZES_MAP[isRows ? 0 : 1].put(parComp, new int[][] {ixArr, sizes});
 2306  
         }
 2307  
 
 2308  
         static synchronized int[][] getSizesAndIndexes(Object parComp, boolean isRows)
 2309  
         {
 2310  
                 if (PARENT_ROWCOL_SIZES_MAP == null)
 2311  
                         return null;
 2312  
 
 2313  
                 return (int[][]) PARENT_ROWCOL_SIZES_MAP[isRows ? 0 : 1].get(parComp);
 2314  
         }
 2315  
 
 2316  
         private static WeakHashMap<Object, LinkedHashMap<Integer, Cell>> PARENT_GRIDPOS_MAP = null;
 2317  
         private static synchronized void saveGrid(ComponentWrapper parComp, LinkedHashMap<Integer, Cell> grid)
 2318  
         {
 2319  
                 if (PARENT_GRIDPOS_MAP == null)    // Lazy since only if designing in IDEs
 2320  
                         PARENT_GRIDPOS_MAP = new WeakHashMap<Object, LinkedHashMap<Integer, Cell>>();
 2321  
 
 2322  
                 PARENT_GRIDPOS_MAP.put(parComp.getComponent(), grid);
 2323  
         }
 2324  
 
 2325  
         static synchronized HashMap<Object, int[]> getGridPositions(Object parComp)
 2326  
         {
 2327  
                 if (PARENT_GRIDPOS_MAP == null)
 2328  
                         return null;
 2329  
 
 2330  
                 LinkedHashMap<Integer, Cell> grid = PARENT_GRIDPOS_MAP.get(parComp);
 2331  
                 if (grid == null)
 2332  
                         return null;
 2333  
 
 2334  
                 HashMap<Object, int[]> retMap = new HashMap<Object,int[]>();
 2335  
 
 2336  
                 for (Map.Entry<Integer, Cell> e : grid.entrySet()) {
 2337  
                         Cell cell = e.getValue();
 2338  
                         Integer xyInt = e.getKey();
 2339  
                         if (xyInt != null) {
 2340  
                                 int x = xyInt & 0x0000ffff;
 2341  
                                 int y = xyInt >> 16;
 2342  
 
 2343  
                                 for (CompWrap cw : cell.compWraps)
 2344  
                                         retMap.put(cw.comp.getComponent(), new int[]{x, y, cell.spanx, cell.spany});
 2345  
                         }
 2346  
                 }
 2347  
 
 2348  
                 return retMap;
 2349  
         }
 2350  
 }