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 package com.oracle.javafx.scenebuilder.kit.editor.panel.hierarchy.treeview; 33 34 import static com.oracle.javafx.scenebuilder.kit.editor.panel.hierarchy.treeview.HierarchyTreeCell.HIERARCHY_TREE_CELL; 35 import com.oracle.javafx.scenebuilder.kit.util.Deprecation; 36 import java.util.List; 37 import java.util.Set; 38 import javafx.scene.Node; 39 import javafx.scene.control.TreeCell; 40 import javafx.scene.control.TreeItem; 41 import javafx.scene.control.TreeView; 42 43 /** 44 * 45 * p 46 */ 47 public abstract class HierarchyTreeViewUtils { 48 49 /** 50 * Returns the TreeCells for the specified TreeView. 51 * 52 * @param <T> 53 * @param treeView the TreeView owner 54 * @return the TreeCells for the specified TreeView. 55 */ 56 public static <T> Set<Node> getTreeCells(final TreeView<T> treeView) { 57 assert treeView != null; 58 // Looks for the sub nodes which match the CSS selector 59 return treeView.lookupAll("." + HIERARCHY_TREE_CELL); //NOI18N 60 } 61 62 /** 63 * Returns the TreeCell object corresponding to the specified TreeItem. 64 * 65 * @param treeView the TreeView owner 66 * @param treeItem the TreeItem instance 67 * @return the TreeCell object corresponding to the specified TreeItem. 68 */ 69 public static TreeCell<?> getTreeCell(final TreeView<?> treeView, final TreeItem<?> treeItem) { 70 return getTreeCell(getTreeCells(treeView), treeItem); 71 } 72 73 /** 74 * Returns the TreeCell object corresponding to the specified index. 75 * 76 * @param treeView the TreeView owner 77 * @param index the TreeCell index 78 * @return the TreeCell object corresponding to the specified index. 79 */ 80 public static TreeCell<?> getTreeCell(final TreeView<?> treeView, final int index) { 81 return getTreeCell(getTreeCells(treeView), index); 82 } 83 84 /** 85 * Returns the TreeCell object corresponding to the specified TreeItem. 86 * 87 * @param treeCells the set of TreeCells 88 * @param treeItem the TreeItem instance 89 * @return the TreeCell object corresponding to the specified TreeItem. 90 */ 91 public static TreeCell<?> getTreeCell(final Set<Node> treeCells, final TreeItem<?> treeItem) { 92 assert treeCells != null; 93 assert treeItem != null; 94 for (Node node : treeCells) { 95 assert node instanceof TreeCell; 96 final TreeCell<?> treeCell = (TreeCell<?>) node; 97 if (treeItem.getValue() != null 98 && treeItem.getValue().equals(treeCell.getItem())) { 99 return treeCell; 100 } 101 } 102 return null; 103 } 104 105 /** 106 * Returns the TreeCell object corresponding to the specified index. 107 * 108 * @param treeCells the set of TreeCells 109 * @param index the TreeCell index 110 * @return the TreeCell object corresponding to the specified index. 111 */ 112 public static TreeCell<?> getTreeCell(final Set<Node> treeCells, final int index) { 113 assert treeCells != null; 114 for (Node node : treeCells) { 115 assert node instanceof TreeCell; 116 final TreeCell<?> treeCell = (TreeCell<?>) node; 117 if (treeCell.getIndex() == index) { 118 return treeCell; 119 } 120 } 121 return null; 122 } 123 124 /** 125 * Return true if the specified child TreeItem can be reparented to the 126 * specified parent TreeItem. This means that the child TreeItem object is 127 * not in the parent chain of the parent TreeItem. 128 * 129 * @param <T> 130 * @param child 131 * @param parent 132 * @return 133 */ 134 public static <T> boolean canReparentTreeItem(final TreeItem<T> child, TreeItem<T> parent) { 135 if (child == parent) { 136 return false; 137 } 138 int childLevel = Deprecation.getNodeLevel(child); 139 int parentLevel = Deprecation.getNodeLevel(parent); 140 while (parentLevel >= childLevel) { 141 if (parent == child) { 142 return false; 143 } 144 parent = parent.getParent(); 145 parentLevel--; 146 } 147 return true; 148 } 149 150 /** 151 * Return the common parent TreeItem of the specified TreeItems. 152 * 153 * @param <T> 154 * @param treeItems 155 * @return 156 */ 157 public static <T> TreeItem<T> getCommonParentTreeItem( 158 final List<TreeItem<T>> treeItems) { 159 160 assert treeItems != null && !treeItems.isEmpty(); 161 162 // TreeItems contains ROOT 163 // => return ROOT as the common parent 164 for (TreeItem<T> treeItem : treeItems) { 165 if (Deprecation.getNodeLevel(treeItem) == 0) { 166 return treeItem; 167 } 168 } 169 170 // TreeItem single selection 171 // => the common parent is the single TreeItem parent 172 if (treeItems.size() == 1) { 173 return treeItems.get(0).getParent(); 174 } // 175 // TreeItem multi selection 176 else { 177 assert treeItems.size() >= 2; 178 TreeItem<T> parent = null; 179 TreeItem<T> child = treeItems.get(0); 180 for (int index = 1; index < treeItems.size(); index++) { 181 parent = getCommonParentTreeItem(child, treeItems.get(index)); 182 // We reached the ROOT level 183 // => common parent is ROOT TreeItem 184 if (Deprecation.getNodeLevel(parent) == 0) { 185 break; 186 } else { 187 child = parent; 188 } 189 } 190 return parent; 191 } 192 } 193 194 private static <T> TreeItem<T> getCommonParentTreeItem( 195 final TreeItem<T> child1, 196 final TreeItem<T> child2) { 197 198 assert child1 != null && child2 != null; 199 200 int child1Level = Deprecation.getNodeLevel(child1); 201 int child2Level = Deprecation.getNodeLevel(child2); 202 // Neither child1 nor child2 is ROOT TreeItem 203 assert child1Level > 0 && child2Level > 0; 204 205 TreeItem<T> parent1 = child1.getParent(); 206 TreeItem<T> parent2 = child2.getParent(); 207 208 if (child1Level < child2Level) { 209 while (child1Level < child2Level) { 210 parent2 = parent2.getParent(); 211 child2Level--; 212 } 213 // We reached the common parent TreeItem 214 if (parent1 == parent2) { 215 return parent1; 216 } else { 217 // At this step, parent1 and parent2 have same node level 218 // within the TreeView 219 while (parent1 != parent2) { 220 parent1 = parent1.getParent(); 221 parent2 = parent2.getParent(); 222 } 223 return parent1; 224 } 225 } else { 226 while (child1Level > child2Level) { 227 parent1 = parent1.getParent(); 228 child1Level--; 229 } 230 // We reached the common parent TreeItem 231 if (parent1 == parent2) { 232 return parent1; 233 } else { 234 // At this step, parent1 and parent2 have same node level 235 // within the TreeView 236 while (parent1 != parent2) { 237 parent1 = parent1.getParent(); 238 parent2 = parent2.getParent(); 239 } 240 return parent1; 241 } 242 } 243 } 244 }