1 /* 2 * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.javafx.scene; 27 28 import com.sun.glass.ui.Accessible; 29 import com.sun.javafx.geom.BaseBounds; 30 import com.sun.javafx.geom.PickRay; 31 import com.sun.javafx.geom.transform.BaseTransform; 32 import com.sun.javafx.scene.input.PickResultChooser; 33 import com.sun.javafx.scene.traversal.Direction; 34 import com.sun.javafx.sg.prism.NGNode; 35 import com.sun.javafx.util.Utils; 36 import java.util.List; 37 import java.util.Map; 38 import javafx.beans.binding.BooleanExpression; 39 import javafx.beans.property.BooleanProperty; 40 import javafx.css.CssMetaData; 41 import javafx.css.Style; 42 import javafx.css.Styleable; 43 import javafx.css.StyleableProperty; 44 import javafx.geometry.Bounds; 45 import javafx.scene.Node; 46 import javafx.scene.SubScene; 47 import javafx.scene.shape.Shape; 48 import javafx.scene.shape.Shape3D; 49 50 /** 51 * Used to access internal methods of Node. 52 */ 53 public abstract class NodeHelper { 54 private static NodeAccessor nodeAccessor; 55 56 static { 57 Utils.forceInit(Node.class); 58 } 59 60 protected NodeHelper() { 61 } 62 63 protected static NodeHelper getHelper(Node node) { 64 65 NodeHelper helper = nodeAccessor.getHelper(node); 66 if (helper == null) { 67 String nodeType; 68 if (node instanceof Shape) { 69 nodeType = "Shape"; 70 } else if (node instanceof Shape3D) { 71 nodeType = "Shape3D"; 72 } else { 73 nodeType = "Node"; 74 } 75 76 throw new UnsupportedOperationException( 77 "Applications should not extend the " 78 + nodeType + " class directly."); 79 } 80 return helper; 81 } 82 83 protected static void setHelper(Node node, NodeHelper nodeHelper) { 84 nodeAccessor.setHelper(node, nodeHelper); 85 } 86 87 /* 88 * Static helper methods for cases where the implementation is done in an 89 * instance method that is overridden by subclasses. 90 * These methods exist in the base class only. 91 */ 92 93 public static NGNode createPeer(Node node) { 94 return getHelper(node).createPeerImpl(node); 95 } 96 97 public static void markDirty(Node node, DirtyBits dirtyBit) { 98 getHelper(node).markDirtyImpl(node, dirtyBit); 99 } 100 101 public static void updatePeer(Node node) { 102 getHelper(node).updatePeerImpl(node); 103 } 104 105 public static Bounds computeLayoutBounds(Node node) { 106 return getHelper(node).computeLayoutBoundsImpl(node); 107 } 108 109 /* 110 * Computes the geometric bounds for this Node. This method is abstract 111 * and must be implemented by each Node subclass. 112 */ 113 public static BaseBounds computeGeomBounds(Node node, 114 BaseBounds bounds, BaseTransform tx) { 115 return getHelper(node).computeGeomBoundsImpl(node, bounds, tx); 116 } 117 118 public static void transformsChanged(Node node) { 119 getHelper(node).transformsChangedImpl(node); 120 } 121 122 public static boolean computeContains(Node node, double localX, double localY) { 123 return getHelper(node).computeContainsImpl(node, localX, localY); 124 } 125 126 public static void pickNodeLocal(Node node, PickRay localPickRay, 127 PickResultChooser result) { 128 getHelper(node).pickNodeLocalImpl(node, localPickRay, result); 129 } 130 131 public static boolean computeIntersects(Node node, PickRay pickRay, 132 PickResultChooser pickResult) { 133 return getHelper(node).computeIntersectsImpl(node, pickRay, pickResult); 134 } 135 136 public static void geomChanged(Node node) { 137 getHelper(node).geomChangedImpl(node); 138 } 139 140 public static void notifyLayoutBoundsChanged(Node node) { 141 getHelper(node).notifyLayoutBoundsChangedImpl(node); 142 } 143 144 public static void processCSS(Node node) { 145 getHelper(node).processCSSImpl(node); 146 } 147 148 /* 149 * Methods that will be overridden by subclasses 150 */ 151 152 protected abstract NGNode createPeerImpl(Node node); 153 protected abstract boolean computeContainsImpl(Node node, double localX, double localY); 154 protected abstract BaseBounds computeGeomBoundsImpl(Node node, 155 BaseBounds bounds, BaseTransform tx); 156 157 protected void markDirtyImpl(Node node, DirtyBits dirtyBit) { 158 nodeAccessor.doMarkDirty(node, dirtyBit); 159 } 160 161 protected void updatePeerImpl(Node node) { 162 nodeAccessor.doUpdatePeer(node); 163 } 164 165 protected Bounds computeLayoutBoundsImpl(Node node) { 166 return nodeAccessor.doComputeLayoutBounds(node); 167 } 168 169 protected void transformsChangedImpl(Node node) { 170 nodeAccessor.doTransformsChanged(node); 171 } 172 173 protected void pickNodeLocalImpl(Node node, PickRay localPickRay, 174 PickResultChooser result) { 175 nodeAccessor.doPickNodeLocal(node, localPickRay, result); 176 } 177 178 protected boolean computeIntersectsImpl(Node node, PickRay pickRay, 179 PickResultChooser pickResult) { 180 return nodeAccessor.doComputeIntersects(node, pickRay, pickResult); 181 } 182 183 protected void geomChangedImpl(Node node) { 184 nodeAccessor.doGeomChanged(node); 185 } 186 187 protected void notifyLayoutBoundsChangedImpl(Node node) { 188 nodeAccessor.doNotifyLayoutBoundsChanged(node); 189 } 190 191 protected void processCSSImpl(Node node) { 192 nodeAccessor.doProcessCSS(node); 193 } 194 195 /* 196 * Methods used by Node (base) class only 197 */ 198 199 public static boolean isDirty(Node node, DirtyBits dirtyBit) { 200 return nodeAccessor.isDirty(node, dirtyBit); 201 } 202 203 public static boolean isDirtyEmpty(Node node) { 204 return nodeAccessor.isDirtyEmpty(node); 205 } 206 207 public static void syncPeer(Node node) { 208 nodeAccessor.syncPeer(node); 209 } 210 211 public static <P extends NGNode> P getPeer(Node node) { 212 return nodeAccessor.getPeer(node); 213 } 214 215 public static BaseTransform getLeafTransform(Node node) { 216 return nodeAccessor.getLeafTransform(node); 217 } 218 219 public static void layoutBoundsChanged(Node node) { 220 nodeAccessor.layoutBoundsChanged(node); 221 } 222 223 public static void setShowMnemonics(Node node, boolean value) { 224 nodeAccessor.setShowMnemonics(node, value); 225 } 226 227 public static boolean isShowMnemonics(Node node) { 228 return nodeAccessor.isShowMnemonics(node); 229 } 230 231 public static BooleanProperty showMnemonicsProperty(Node node) { 232 return nodeAccessor.showMnemonicsProperty(node); 233 } 234 235 public static boolean traverse(Node node, Direction direction) { 236 return nodeAccessor.traverse(node, direction); 237 } 238 239 public static double getPivotX(Node node) { 240 return nodeAccessor.getPivotX(node); 241 } 242 243 public static double getPivotY(Node node) { 244 return nodeAccessor.getPivotY(node); 245 } 246 247 public static double getPivotZ(Node node) { 248 return nodeAccessor.getPivotZ(node); 249 } 250 251 public static void pickNode(Node node, PickRay pickRay, 252 PickResultChooser result) { 253 nodeAccessor.pickNode(node, pickRay, result); 254 } 255 256 public static boolean intersects(Node node, PickRay pickRay, 257 PickResultChooser pickResult) { 258 return nodeAccessor.intersects(node, pickRay, pickResult); 259 } 260 261 public static double intersectsBounds(Node node, PickRay pickRay) { 262 return nodeAccessor.intersectsBounds(node, pickRay); 263 } 264 265 public static void layoutNodeForPrinting(Node node) { 266 nodeAccessor.layoutNodeForPrinting(node); 267 } 268 269 public static boolean isDerivedDepthTest(Node node) { 270 return nodeAccessor.isDerivedDepthTest(node); 271 } 272 273 public static SubScene getSubScene(Node node) { 274 return nodeAccessor.getSubScene(node); 275 } 276 277 public static Accessible getAccessible(Node node) { 278 return nodeAccessor.getAccessible(node); 279 } 280 281 public static void reapplyCSS(Node node) { 282 nodeAccessor.reapplyCSS(node); 283 } 284 285 public static boolean isTreeVisible(Node node) { 286 return nodeAccessor.isTreeVisible(node); 287 } 288 289 public static BooleanExpression treeVisibleProperty(Node node) { 290 return nodeAccessor.treeVisibleProperty(node); 291 } 292 293 public static boolean isTreeShowing(Node node) { 294 return nodeAccessor.isTreeShowing(node); 295 } 296 297 public static BooleanExpression treeShowingProperty(Node node) { 298 return nodeAccessor.treeShowingProperty(node); 299 } 300 301 public static List<Style> getMatchingStyles(CssMetaData cssMetaData, Styleable styleable) { 302 return nodeAccessor.getMatchingStyles(cssMetaData, styleable); 303 } 304 305 public static Map<StyleableProperty<?>,List<Style>> findStyles(Node node, Map<StyleableProperty<?>,List<Style>> styleMap) { 306 return nodeAccessor.findStyles(node, styleMap); 307 } 308 309 public static void setNodeAccessor(final NodeAccessor newAccessor) { 310 if (nodeAccessor != null) { 311 throw new IllegalStateException(); 312 } 313 314 nodeAccessor = newAccessor; 315 } 316 317 public static NodeAccessor getNodeAccessor() { 318 if (nodeAccessor == null) { 319 throw new IllegalStateException(); 320 } 321 322 return nodeAccessor; 323 } 324 325 public interface NodeAccessor { 326 NodeHelper getHelper(Node node); 327 void setHelper(Node node, NodeHelper nodeHelper); 328 void doMarkDirty(Node node, DirtyBits dirtyBit); 329 void doUpdatePeer(Node node); 330 BaseTransform getLeafTransform(Node node); 331 Bounds doComputeLayoutBounds(Node node); 332 void doTransformsChanged(Node node); 333 void doPickNodeLocal(Node node, PickRay localPickRay, 334 PickResultChooser result); 335 boolean doComputeIntersects(Node node, PickRay pickRay, 336 PickResultChooser pickResult); 337 void doGeomChanged(Node node); 338 void doNotifyLayoutBoundsChanged(Node node); 339 void doProcessCSS(Node node); 340 boolean isDirty(Node node, DirtyBits dirtyBit); 341 boolean isDirtyEmpty(Node node); 342 void syncPeer(Node node); 343 <P extends NGNode> P getPeer(Node node); 344 void layoutBoundsChanged(Node node); 345 void setShowMnemonics(Node node, boolean value); 346 boolean isShowMnemonics(Node node); 347 BooleanProperty showMnemonicsProperty(Node node); 348 boolean traverse(Node node, Direction direction); 349 double getPivotX(Node node); 350 double getPivotY(Node node); 351 double getPivotZ(Node node); 352 void pickNode(Node node, PickRay pickRay, PickResultChooser result); 353 boolean intersects(Node node, PickRay pickRay, PickResultChooser pickResult); 354 double intersectsBounds(Node node, PickRay pickRay); 355 void layoutNodeForPrinting(Node node); 356 boolean isDerivedDepthTest(Node node); 357 SubScene getSubScene(Node node); 358 void setLabeledBy(Node node, Node labeledBy); 359 Accessible getAccessible(Node node); 360 void reapplyCSS(Node node); 361 boolean isTreeVisible(Node node); 362 BooleanExpression treeVisibleProperty(Node node); 363 boolean isTreeShowing(Node node); 364 BooleanExpression treeShowingProperty(Node node); 365 List<Style> getMatchingStyles(CssMetaData cssMetaData, Styleable styleable); 366 Map<StyleableProperty<?>,List<Style>> findStyles(Node node, 367 Map<StyleableProperty<?>,List<Style>> styleMap); 368 } 369 370 }