1 /* 2 * Copyright (c) 2012, 2014, Oracle and/or its affiliates. 3 * All rights reserved. Use is subject to license terms. 4 * 5 * This file is available and licensed under the following license: 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * - Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * - Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the distribution. 16 * - Neither the name of Oracle Corporation nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 package com.oracle.javafx.scenebuilder.kit.editor.panel.content.driver.resizer; 34 35 import java.util.HashMap; 36 import java.util.List; 37 import java.util.Map; 38 39 import javafx.geometry.Bounds; 40 import javafx.scene.control.TableColumnBase; 41 import javafx.scene.control.TreeTableColumn; 42 import javafx.scene.layout.Region; 43 44 import com.oracle.javafx.scenebuilder.kit.editor.panel.content.driver.TreeTableViewDesignInfoX; 45 import com.oracle.javafx.scenebuilder.kit.metadata.util.PropertyName; 46 import com.oracle.javafx.scenebuilder.kit.util.MathUtils; 47 48 /** 49 * 50 */ 51 public class TreeTableColumnResizer { 52 53 private static final PropertyName minWidthName = new PropertyName("minWidth"); //NOI18N 54 private static final PropertyName prefWidthName = new PropertyName("prefWidth"); //NOI18N 55 private static final PropertyName maxWidthName = new PropertyName("maxWidth"); //NOI18N 56 57 private final TreeTableColumn<?,?> treeTableColumn; 58 private final TreeTableColumn<?,?> treeTableColumnNext; 59 private final ColumnSizing originalSizing; // Column at columnIndex 60 private final ColumnSizing originalSizingNext; // Column at columnIndex+1 (if any) 61 private final double x1, x2, x3; 62 63 public TreeTableColumnResizer(TreeTableColumn<?,?> treeTableColumn) { 64 assert treeTableColumn != null; 65 assert treeTableColumn.getTreeTableView() != null; 66 67 this.treeTableColumn = treeTableColumn; 68 this.originalSizing = new ColumnSizing(this.treeTableColumn); 69 70 final List<?> columns; 71 if (this.treeTableColumn.getParentColumn() != null) { 72 columns = this.treeTableColumn.getParentColumn().getColumns(); 73 } else { 74 columns = this.treeTableColumn.getTreeTableView().getColumns(); 75 } 76 final int columnIndex = columns.indexOf(this.treeTableColumn); 77 if (columnIndex+1 < columns.size()) { 78 this.treeTableColumnNext = (TreeTableColumn<?,?>)columns.get(columnIndex+1); 79 this.originalSizingNext = new ColumnSizing(this.treeTableColumnNext); 80 } else { 81 this.treeTableColumnNext = null; 82 this.originalSizingNext = null; 83 } 84 85 // 86 // Case #1 : treeTableColumnNext != null 87 // 88 // x1 x2 x3 89 // --+-----------------+------------------------+-- 90 // | col n | col n+1 | 91 // | | | 92 // 93 // Range for moving x2 is [x1, x3] 94 // 95 // 96 // Case #2 : treeTableColumnNext == null 97 // 98 // Case #2.1: treeTableColumn.getParentColumn() != null 99 // 100 // x1 x2 x3 101 // --+-----------------+ | 102 // | col n | | 103 // | | | 104 // parentColumn maxX 105 // 106 // 107 // Case #2.2: treeTableColumn.getParentColumn() == null 108 // 109 // x1 x2 x3 110 // --+-----------------+ | 111 // | col n | | 112 // | | | 113 // treeTableView maxX 114 // 115 // Range for moving x2 is [x1, x3] 116 // 117 // 118 119 final TreeTableViewDesignInfoX di = new TreeTableViewDesignInfoX(); 120 final Bounds columnBounds = di.getColumnBounds(treeTableColumn); 121 x1 = columnBounds.getMinX(); 122 x2 = columnBounds.getMaxX(); 123 if (treeTableColumnNext != null) { 124 final Bounds nextBounds = di.getColumnBounds(treeTableColumnNext); 125 x3 = nextBounds.getMaxX(); 126 } else { 127 if (treeTableColumn.getParentColumn() != null) { 128 final TableColumnBase<?,?> parentColumn 129 = (TableColumnBase<?,?>) this.treeTableColumn.getParentColumn(); 130 assert parentColumn instanceof TreeTableColumn<?,?>; 131 final Bounds parentBounds = di.getColumnBounds((TreeTableColumn<?,?>)parentColumn); 132 x3 = parentBounds.getMaxX(); 133 } else { 134 final Bounds layoutBounds = treeTableColumn.getTreeTableView().getLayoutBounds(); 135 x3 = layoutBounds.getMaxX(); 136 } 137 } 138 } 139 140 public TreeTableColumn<?,?> getTreeTableColumn() { 141 return treeTableColumn; 142 } 143 144 public void updateWidth(double dx) { 145 146 // Clamp x2 + dx in [x1, x3] 147 final double newX2 = Math.max(x1, Math.min(x3, x2 + dx)); 148 final double newWidth = newX2 - x1; 149 final double newWidthNext = x3 - newX2; 150 151 // assert (newCellWidth+newNextWidth) == (downColWidths[colIndex]+downColWidths[colIndex+1]) : 152 // "newCellWidth+newNextWidth=" + (newCellWidth+newNextWidth) + ", " + 153 // "downColWidths[colIndex]+downColWidths[colIndex+1]=" + 154 // (downColWidths[colIndex]+downColWidths[colIndex+1]); 155 156 // Updates width of treeTableColumn 157 treeTableColumn.setPrefWidth(newWidth); 158 if (treeTableColumn.getMinWidth() == Region.USE_COMPUTED_SIZE) { 159 treeTableColumn.setMinWidth(newWidth); 160 } else { 161 treeTableColumn.setMinWidth(Math.min(newWidth, treeTableColumn.getMinWidth())); 162 } 163 if (treeTableColumn.getMaxWidth() == Region.USE_COMPUTED_SIZE) { 164 treeTableColumn.setMaxWidth(newWidth); 165 } else { 166 treeTableColumn.setMaxWidth(Math.max(newWidth, treeTableColumn.getMaxWidth())); 167 } 168 169 // Updates with of treeTableColumnNext 170 if (treeTableColumnNext != null) { 171 treeTableColumnNext.setPrefWidth(newWidthNext); 172 if (treeTableColumnNext.getMinWidth() == Region.USE_COMPUTED_SIZE) { 173 treeTableColumnNext.setMinWidth(newWidthNext); 174 } else { 175 treeTableColumnNext.setMinWidth(Math.min(newWidthNext, treeTableColumnNext.getMinWidth())); 176 } 177 if (treeTableColumnNext.getMaxWidth() == Region.USE_COMPUTED_SIZE) { 178 treeTableColumnNext.setMaxWidth(newWidthNext); 179 } else { 180 treeTableColumnNext.setMaxWidth(Math.max(newWidthNext, treeTableColumnNext.getMaxWidth())); 181 } 182 } 183 } 184 185 public void revertToOriginalSize() { 186 originalSizing.applyTo(treeTableColumn); 187 if (treeTableColumnNext != null) { 188 originalSizingNext.applyTo(treeTableColumnNext); 189 } 190 } 191 192 193 public Map<PropertyName, Object> getChangeMap() { 194 final Map<PropertyName, Object> result = new HashMap<>(); 195 196 if (MathUtils.equals(treeTableColumn.getMinWidth(), originalSizing.getMinWidth()) == false) { 197 result.put(minWidthName, treeTableColumn.getMinWidth()); 198 } 199 if (MathUtils.equals(treeTableColumn.getPrefWidth(), originalSizing.getPrefWidth()) == false) { 200 result.put(prefWidthName, treeTableColumn.getPrefWidth()); 201 } 202 if (MathUtils.equals(treeTableColumn.getMaxWidth(), originalSizing.getMaxWidth()) == false) { 203 result.put(maxWidthName, treeTableColumn.getMaxWidth()); 204 } 205 return result; 206 } 207 208 209 public Map<PropertyName, Object> getChangeMapNext() { 210 final Map<PropertyName, Object> result = new HashMap<>(); 211 212 if (treeTableColumnNext != null) { 213 if (MathUtils.equals(treeTableColumnNext.getMinWidth(), originalSizingNext.getMinWidth()) == false) { 214 result.put(minWidthName, treeTableColumnNext.getMinWidth()); 215 } 216 if (MathUtils.equals(treeTableColumnNext.getPrefWidth(), originalSizingNext.getPrefWidth()) == false) { 217 result.put(prefWidthName, treeTableColumnNext.getPrefWidth()); 218 } 219 if (MathUtils.equals(treeTableColumnNext.getMaxWidth(), originalSizingNext.getMaxWidth()) == false) { 220 result.put(maxWidthName, treeTableColumnNext.getMaxWidth()); 221 } 222 } 223 224 return result; 225 } 226 227 228 /* 229 * Private 230 */ 231 232 private static class ColumnSizing { 233 private final double minWidth; 234 private final double maxWidth; 235 private final double prefWidth; 236 237 public ColumnSizing(TreeTableColumn<?,?> tc) { 238 this.minWidth = tc.getMinWidth(); 239 this.maxWidth = tc.getMaxWidth(); 240 this.prefWidth = tc.getPrefWidth(); 241 } 242 243 public double getMinWidth() { 244 return minWidth; 245 } 246 247 public double getMaxWidth() { 248 return maxWidth; 249 } 250 251 public double getPrefWidth() { 252 return prefWidth; 253 } 254 255 public void applyTo(TreeTableColumn<?,?> tc) { 256 tc.setMinWidth(minWidth); 257 tc.setMaxWidth(maxWidth); 258 tc.setPrefWidth(prefWidth); 259 } 260 } 261 }