public static final Callback CONSTRAINED_RESIZE_POLICY = new Callback() { -private boolean isFirstRun = true; @Override public String toString() { return "constrained-resize"; } @Override public Boolean call(ResizeFeatures prop) { TableView table = prop.getTable(); TableColumn column = prop.getColumn(); double delta = prop.getDelta(); /* * There are two phases to the constrained resize policy: * 1) Ensuring internal consistency (i.e. table width == sum of all visible * columns width). This is often called when the table is resized. * 2) Resizing the given column by __up to__ the given delta. * * It is possible that phase 1 occur and there be no need for phase 2 to * occur. */ boolean isShrinking; double target; double totalLowerBound = 0; double totalUpperBound = 0; double tableWidth = table.contentWidth; if (tableWidth == 0) return false; /* * PHASE 1: Check to ensure we have internal consistency. Based on the * Swing JTable implementation. */ // determine the width of all visible columns, and their preferred width double colWidth = 0; for (TableColumn col : table.getVisibleLeafColumns()) { colWidth += col.getWidth(); } if (Math.abs(colWidth - tableWidth) > 1) { isShrinking = colWidth > tableWidth; target = tableWidth; - if (isFirstRun) { - // if we are here we have an inconsistency - these two values should be - // equal when this resizing policy is being used. - for (TableColumn col : table.getVisibleLeafColumns()) { - totalLowerBound += col.getMinWidth(); - totalUpperBound += col.getMaxWidth(); - } - - // We run into trouble if the numbers are set to infinity later on - totalUpperBound = totalUpperBound == Double.POSITIVE_INFINITY ? - Double.MAX_VALUE : - (totalUpperBound == Double.NEGATIVE_INFINITY ? Double.MIN_VALUE : totalUpperBound); - - for (TableColumn col : table.getVisibleLeafColumns()) { - double lowerBound = col.getMinWidth(); - double upperBound = col.getMaxWidth(); - - // Check for zero. This happens when the distribution of the delta - // finishes early due to a series of "fixed" entries at the end. - // In this case, lowerBound == upperBound, for all subsequent terms. - double newSize; - if (totalLowerBound == totalUpperBound) { - newSize = lowerBound; - } else { - double f = (target - totalLowerBound) / (totalUpperBound - totalLowerBound); - newSize = Math.round(lowerBound + f * (upperBound - lowerBound)); - } - - double remainder = resize(col, newSize - col.getWidth()); - - target -= newSize + remainder; - totalLowerBound -= lowerBound; - totalUpperBound -= upperBound; - } - - isFirstRun = false; - } else { double actualDelta = tableWidth - colWidth; List> cols = ((TableView)table).getVisibleLeafColumns(); resizeColumns(cols, actualDelta); - } } // At this point we can be happy in the knowledge that we have internal // consistency, i.e. table width == sum of the width of all visible // leaf columns. /* * Column may be null if we just changed the resize policy, and we * just wanted to enforce internal consistency, as mentioned above. */ if (column == null) { return false; } /* * PHASE 2: Handling actual column resizing (by the user). Based on my own * implementation (based on the UX spec). */ isShrinking = delta < 0; // need to find the first leaf column of the given column - it is this // column that we actually resize from. If this column is a leaf, then we // use it. TableColumn leafColumn = column; while (leafColumn.getColumns().size() > 0) { leafColumn = leafColumn.getColumns().get(0); } int colPos = table.getVisibleLeafColumns().indexOf(leafColumn); int endColPos = table.getVisibleLeafColumns().size() - 1; // System.out.println("resizing " + leafColumn.getText() + ". colPos: " + colPos + ", endColPos: " + endColPos); // we now can split the observableArrayList into two subobservableArrayLists, representing all // columns that should grow, and all columns that should shrink // var growingCols = if (isShrinking) // then table.visibleLeafColumns[colPos+1..endColPos] // else table.visibleLeafColumns[0..colPos]; // var shrinkingCols = if (isShrinking) // then table.visibleLeafColumns[0..colPos] // else table.visibleLeafColumns[colPos+1..endColPos]; double remainingDelta = delta; while (endColPos > colPos && remainingDelta != 0) { TableColumn resizingCol = table.getVisibleLeafColumns().get(endColPos); endColPos--; // if the column width is fixed, break out and try the next column if (! resizingCol.isResizable()) continue; // for convenience we discern between the shrinking and growing columns TableColumn shrinkingCol = isShrinking ? leafColumn : resizingCol; TableColumn growingCol = !isShrinking ? leafColumn : resizingCol; // (shrinkingCol.width == shrinkingCol.minWidth) or (growingCol.width == growingCol.maxWidth) if (growingCol.getWidth() > growingCol.getPrefWidth()) { // growingCol is willing to be generous in this case - it goes // off to find a potentially better candidate to grow List seq = table.getVisibleLeafColumns().subList(colPos + 1, endColPos + 1); for (int i = seq.size() - 1; i >= 0; i--) { TableColumn c = (TableColumn)seq.get(i); if (c.getWidth() < c.getPrefWidth()) { growingCol = c; break; } } } // // if (shrinkingCol.width < shrinkingCol.prefWidth) { // for (c in reverse table.visibleLeafColumns[colPos+1..endColPos]) { // if (c.width > c.prefWidth) { // shrinkingCol = c; // break; // } // } // } double sdiff = Math.min(Math.abs(remainingDelta), shrinkingCol.getWidth() - shrinkingCol.getMinWidth()); // System.out.println("\tshrinking " + shrinkingCol.getText() + " and growing " + growingCol.getText()); // System.out.println("\t\tMath.min(Math.abs("+remainingDelta+"), "+shrinkingCol.getWidth()+" - "+shrinkingCol.getMinWidth()+") = " + sdiff); double delta1 = resize(shrinkingCol, -sdiff); double delta2 = resize(growingCol, sdiff); remainingDelta += isShrinking ? sdiff : -sdiff; } return remainingDelta == 0; } };