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.css; 33 34 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMObject; 35 import com.oracle.javafx.scenebuilder.kit.util.CssInternal; 36 import com.oracle.javafx.scenebuilder.kit.util.Deprecation; 37 import java.util.Set; 38 import javafx.css.CssMetaData; 39 import javafx.css.Styleable; 40 import javafx.css.StyleableProperty; 41 import javafx.scene.Group; 42 import javafx.scene.Node; 43 import javafx.scene.Parent; 44 import javafx.scene.control.MenuItem; 45 import javafx.scene.control.PopupControl; 46 import javafx.scene.control.Tab; 47 import javafx.scene.control.TabPane; 48 import javafx.scene.layout.Pane; 49 50 /** 51 * CSS support for Scene Builder. 52 * 53 * @treatAsPrivate 54 */ 55 public class CssUtils { 56 57 private CssUtils() { 58 assert false; 59 } 60 61 // /** 62 // * This method is used to create a barrier between the SB and the user scene graph. 63 // * @param parent 64 // */ 65 // public static Group createCSSFrontier(){ 66 // Group grp = Deprecation.createGroupWithNullParentStylesheets(); 67 // /* 68 // * Doing so, when caspian lookup resolution occurs for a Node D&D from a SB user, 69 // * if there is no redefinition in the Author space, 70 // * then this container is reached and the caspian lookups are resolved. 71 // */ 72 // grp.getStyleClass().add("root"); //NOI18N 73 // return grp; 74 // } 75 // 76 // // Reseting is the process to set the value to its initial value. 77 // private static <N extends Node> void resetCssProperty(N node, CssMetaData<N,?> p) { 78 // try { 79 // Object val = getResetValue(node, p); 80 // @SuppressWarnings("unchecked") //NOI18N 81 // CssMetaData<Node, Object> sp = (CssMetaData<Node, Object>) p; 82 // if (sp.isSettable(node)) { 83 // sp.getStyleableProperty(node).applyStyle(StyleOrigin.USER_AGENT, val); 84 // } 85 // } catch (RuntimeException ex) { 86 // Utils.println("Can't reset property " + p.getProperty() + " on " + node.getClass() + ": " + ex.toString()); //NOI18N 87 // } 88 // } 89 // 90 // private static <N extends Node> Object getResetValue(N node, CssMetaData<N, ?> sp) { 91 // // The best value depends on the nature of the property. 92 // // If this is a styleable only property with no bean property associated 93 // // then we need to use the initialValue. 94 // // If there is a Prop, then use it as the reset value. 95 // // See DTL-4049 and DTL-4087 96 // StyleableProperty<?> property = sp.getStyleableProperty(node); 97 // Object value = sp.getInitialValue(node); 98 // StyleOrigin orig = property.getStyleOrigin(); 99 // if (StyleOrigin.AUTHOR != orig && StyleOrigin.INLINE != orig) { 100 // // Do we have a Prop? 101 // String name = ((ReadOnlyProperty) property).getName(); 102 // try { 103 // Prop.of(node, name); 104 // value = property.getValue(); 105 // } catch (IllegalArgumentException ex) { 106 // //OK, no prop, need initial value. 107 // } 108 // } 109 // return value; 110 // } 111 // 112 // /** 113 // * Will try first to put the property in a state that makes it OK 114 // * to receive USER AGENT styling. 115 // * If this is not possible, will call prop.set(bean, value); 116 // * @param bean 117 // * @param prop 118 // * @param value 119 // */ 120 // public static void setProperty(Object bean, Prop prop, Object value) { 121 // if (bean != null) { 122 // boolean set = false; 123 // try { 124 // ObservableValue<?> beanProp = prop.model(bean); 125 // if (beanProp instanceof StyleableProperty) { 126 // Styleable styleable = getStyleable(bean); 127 // if(styleable != null){ 128 // Node stylableNode = Deprecation.getNode(styleable); 129 // if (stylableNode == null) { 130 // stylableNode = getNode(bean); 131 // } 132 // @SuppressWarnings("unchecked") //NOI18N 133 // CssMetaData<Node, Object> sp = (CssMetaData<Node, Object>) ((StyleableProperty)beanProp).getCssMetaData(); 134 // if (sp != null && stylableNode != null) { 135 // if (sp.isSettable(stylableNode)) { 136 // sp.getStyleableProperty(stylableNode).applyStyle(StyleOrigin.USER_AGENT, value); 137 // } 138 // set = true; 139 // } 140 // } 141 // } 142 // } catch (RuntimeException ex) { 143 // Utils.println("can't set Bean property " + prop.name + " on " + bean.getClass() + " :" + ex.toString()); //NOI18N 144 // } 145 // 146 // if(!set){ 147 // prop.set(bean, value); 148 // } 149 // } 150 // } 151 static String getBeanPropertyName(Node node, CssMetaData<?, ?> sp) { 152 String property = null; 153 try { 154 @SuppressWarnings("unchecked") 155 CssMetaData<Node, Object> raw = (CssMetaData<Node, Object>) sp; 156 final StyleableProperty<Object> val = raw.getStyleableProperty(node); 157 property = CssInternal.getBeanPropertyName(val); 158 } catch (RuntimeException ex) { 159 System.out.println("Can't retrieve property " + ex); //NOI18N 160 } 161 return property; 162 } 163 164 // private static void resetSkinNode(Node node) { 165 // for (CssMetaData<?,?> p : node.getCssMetaData()) { 166 // @SuppressWarnings("unchecked") //NOI18N 167 // final CssMetaData<Node, ?> sp = (CssMetaData<Node, ?>) p; 168 // resetCssProperty(node, sp); 169 // } 170 // } 171 // 172 // private static void resetSubStructure(Node n) { 173 // // We need to skip Elements tha tcan be present in the Skin (eg: Content 174 // // of the Tab. 175 // if (!n.getStyleClass().isEmpty() && Element.forNode(n) == null) { 176 // resetSkinNode(n); 177 // } 178 // if (n instanceof Parent) { 179 // Parent parentNode = (Parent) n; 180 // for (Node child : parentNode.getChildrenUnmodifiable()) { 181 // resetSubStructure(child); 182 // } 183 // } 184 // } 185 // // Reseting the style of a Node. Any property ruled by a Bean.property 186 // // are not set. This is handled by the SB model (TargetPropertyValue class). 187 // static void resetStyle(Node node) throws RuntimeException { 188 // if (node.getScene() == null) { 189 // return; 190 // } 191 // 192 // // First reset the skin 193 // if (node instanceof Control) { 194 // Node skinNode = getSkinNode((Control) node); 195 // if (skinNode != null) { 196 // // We need to deep dive into the skin to reset properties. 197 // // The caspian ruled properties would be aumaticaly reset 198 // // but the (eg:shape Text used in LabeledSkin) non caspian ruled ones will keep their 199 // // styling. 200 // resetSubStructure(skinNode); 201 // } 202 // } 203 // 204 // // Then properties that are in the control that could suppercede the 205 // // previously set values. 206 // @SuppressWarnings("rawtypes") 207 // final List<CssMetaData<? extends Styleable, ?>> lst = node.getCssMetaData(); 208 // for(CssMetaData<?,?> stp : lst){ 209 // @SuppressWarnings("unchecked") //NOI18N 210 // final CssMetaData<Node, ?> st = (CssMetaData<Node, ?>)stp; 211 // 212 // // Skip the skin 213 // if(st.getProperty().equals("-fx-skin")) { //NOI18N 214 // continue; 215 // } 216 // 217 // @SuppressWarnings("unchecked") //NOI18N 218 // StyleableProperty<?> val = st.getStyleableProperty(node); 219 // boolean needsReset = false; 220 // if(val == null){ // reset property that have no Bean property. 221 // needsReset = true; 222 // } else { 223 // if(val instanceof ReadOnlyProperty){ 224 // // Do we have a Prop? 225 // String name = ((ReadOnlyProperty)val).getName(); 226 // try { 227 // Prop.of(node, name); 228 // }catch(IllegalArgumentException ex){ 229 // //OK, no prop, need reset 230 // needsReset = true; 231 // } 232 // } else {// No prop associated. 233 // needsReset = true; 234 // } 235 // } 236 // if(needsReset){ 237 // resetCssProperty(node, st); 238 // } 239 // } 240 // 241 // // Clear the map from any collected value. 242 // // TODO FX8: the statement below started to trigger NPE since FX8 b68, 243 // // hence the temporary wrap in null check test. Still have to ensure 244 // // it doesn't mask something suspicious. 245 // if (Deprecation.getStyleMap(node) != null) { 246 // Deprecation.getStyleMap(node).clear(); 247 // } 248 // } 249 // 250 // private static Node getSkinNode(Control control) { 251 // Node n = null; 252 // Skin<?> skin = control.getSkin(); 253 // if (skin != null) { 254 // // can happen in unit test 255 // n = skin.getNode(); 256 // } 257 // return n; 258 // } 259 // 260 // public static void editCssRule(Frame frame, CssPropAuthorInfo info) { 261 // try { 262 // if (info.getMainUrl() == null) { 263 // return; 264 // } 265 // File file = new File(info.getMainUrl().toURI()); 266 // Utils.editCssFile(file); 267 // } catch (Exception ex) { 268 // frame.printWarning("messagebar.cannot.edit", ex, info); 269 // } 270 // } 271 // 272 // public static File retrieveCssFile(Frame frame, ComponentPath path, String styleclass) { 273 // // First check in the parent chain. The nearest first. 274 // ComponentPath truncated = path.getNearestParentNodePath(); 275 // for(ComponentReference ref : truncated.getPath()){ 276 // if(ref.getChildComponent() instanceof Parent){ 277 // Parent p = (Parent) ref.getChildComponent(); 278 // // The last element has more priority in CSS application 279 // for (int i = p.getStylesheets().size() - 1; i >= 0; i--) { 280 // String ss = p.getStylesheets().get(i); 281 // try { 282 // URL url = new URL(ss); 283 // Set<String> classes = getStyleClasses(url); 284 // if (classes.contains(styleclass)) { 285 // return new File(url.toURI()); 286 // } 287 // } catch (Exception ex) { 288 // Utils.println("Exception parsing Stylesheet " + ex); //NOI18N 289 // } 290 // } 291 // } 292 // } 293 // List<StyleClasses> styleClasses = STYLECLASSES_SETS.get(getParent(frame)); 294 // File ret = null; 295 // String url = null; 296 // if (styleClasses != null) { 297 // // The last element has more priority in CSS application 298 // for (int i = styleClasses.size()-1; i >= 0; i--) { 299 // StyleClasses sc = styleClasses.get(i); 300 // if (sc.styleClasses.contains(styleclass)) { 301 // url = sc.url; 302 // } 303 // } 304 // if (url != null) { 305 // try { 306 // URI uri = new URI(url); 307 // ret = new File(uri); 308 // } catch (Exception ex) { 309 // // XXX Issue with this URL. 310 // frame.printWarning("messagebar.cannot.retrieve.css.file", url); 311 // } 312 // } 313 // } 314 // return ret; 315 // } 316 // 317 // public static boolean isAuthorStyleClass(Frame frame, ComponentPath path, String item) { 318 // return retrieveCssFile(frame, path, item) != null; 319 // } 320 // 321 // private static class StyleClasses { 322 // 323 // String url; 324 // Set<String> styleClasses; 325 // } 326 // 327 // /* 328 // * Returns the CSS property value defined in the specified style sheet. 329 // * Note that the method returns the first CSS property found in the style sheet : 330 // * - no check is performed on the style class containing the property 331 // * - if the property is defined in several style classes, the first one is returned 332 // */ 333 // public static ParsedValue<?, ?> getValueFor(Stylesheet stylesheet, String property) { 334 // for (Rule rule : stylesheet.getRules()) { 335 // for (Declaration decl : rule.getDeclarations()) { 336 // if (property.equals(decl.getProperty())) { 337 // return decl.getParsedValue(); 338 // } 339 // } 340 // } 341 // return null; 342 // } 343 // 344 // public static ParsedValue<?, ?> getValueFor(String styleClass, String property) { 345 // return getValueFor(STYLE_SHEET_TOOL_CSS, styleClass, property); 346 // } 347 // 348 // public static final String TOOL; 349 // static { 350 // if (Utils.IS_MAC) { 351 // TOOL = "tool-mac"; //NOI18N 352 // } else if (Utils.IS_WINDOWS_XP) { 353 // TOOL = "tool-win-xp"; //NOI18N 354 // } else { 355 // TOOL = "tool"; //NOI18N 356 // } 357 // } 358 // 359 // 360 // public static final String THEME_CSS = Utils.getResourceURL(Frame.class, "css_stylesheets/SceneBuilderTheme.css"); //NOI18N 361 // 362 // public static final String TOOL_ROOT_CSS = Utils.getResourceURL(Frame.class, "css_stylesheets/ToolRoot.css"); //NOI18N 363 // public static final String CONTENT_VIEW_CSS = Utils.getResourceURL(Frame.class, "css_stylesheets/ContentView.css"); //NOI18N 364 // public static final String MESSAGE_BAR_CSS = Utils.getResourceURL(Frame.class, "css_stylesheets/MessageBar.css"); //NOI18N 365 // public static final String LIBRARY_CSS = Utils.getResourceURL(Frame.class, "css_stylesheets/Library.css"); //NOI18N 366 // public static final String HIERARCHY_CSS = Utils.getResourceURL(Frame.class, "css_stylesheets/Hierarchy.css"); //NOI18N 367 // public static final String INSPECTOR_CSS = Utils.getResourceURL(Frame.class, "css_stylesheets/Inspector.css"); //NOI18N 368 // public static final String CSS_VIEWER_CSS = Utils.getResourceURL(Frame.class, "css_stylesheets/CssViewer.css"); //NOI18N 369 // 370 // public static final String POPUP_CSS = Utils.getResourceURL(Frame.class, "css_stylesheets/Popup.css"); //NOI18N 371 // 372 // public static final String SCENE_BUILDER_THEME_STYLECLASS = "SCENE_BUILDER_THEME"; //NOI18N 373 // private static final String SCENE_BUILDER_WIN_FONT_STYLECLASS = "SCENE_BUILDER_WIN_FONT"; //NOI18N 374 // private static final String SCENE_BUILDER_WINXP_FONT_STYLECLASS = "SCENE_BUILDER_WINXP_FONT"; //NOI18N 375 // 376 // public static final String CONTENT_AREA_ID = "JFX_SB_ContentArea"; //NOI18N 377 // private static final String ROOT_STYLECLASS = "root"; //NOI18N 378 // private static Stylesheet STYLE_SHEET_TOOL_CSS = null; 379 // private static final Map<Class<?>, Set<String>> ALTERNATE_STYLECLASSES = new HashMap<>(); 380 // 381 // static Set<FileChooser.ExtensionFilter> SS_EXTENSIONS = 382 // Collections.singleton(new FileChooser.ExtensionFilter(Utils.getI18N().getString("popup.style.sheets"), "*.css", "*.bss")); //NOI18N 383 // 384 // static { 385 // try { 386 // STYLE_SHEET_TOOL_CSS = new CssParser().parse(new URL(TOOL_ROOT_CSS)); 387 // } catch (IOException ex) { 388 // Utils.println("Failed to parse " + TOOL_ROOT_CSS, ex); //NOI18N 389 // } 390 // Set<String> alternates = new HashSet<>(); 391 // alternates.add("floating"); //NOI18N 392 // ALTERNATE_STYLECLASSES.put(TabPane.class, alternates); 393 // } 394 // //Properties that are impacting CSS/Pages. 395 // private static final Set<Prop> CSS_IMPACT = 396 // SetBuilder.<Prop>make(). 397 // add(PropUtils.Parent_STYLESHEETS). 398 // add(PropUtils.Node_ID).add(PropUtils.Styleable_STYLE_CLASS).add(PropUtils.Node_STYLE). 399 // add(PropUtils.Tab_ID).add(PropUtils.Tab_STYLE). 400 // add(PropUtils.PopupControl_ID).add(PropUtils.PopupControl_STYLE). 401 // add(PropUtils.Menu_ITEMS).buildUnmodifiable(); 402 // private static final WeakIdentityHashMap<Parent, List<StyleClasses>> STYLECLASSES_SETS = WeakIdentityHashMap.make(); 403 // 404 // public static void trackNode(final Node node) { 405 // attachMapToNode(node); 406 // } 407 // 408 // public static void stopTrackingNode(Node node) { 409 // @SuppressWarnings("rawtypes") 410 // Map<StyleableProperty<?>, List<Style>> smap = Deprecation.getStyleMap(node); 411 // assert smap != null; 412 // smap.clear(); 413 // } 414 // private static void resetCssState(Element elem) { 415 // resetStyle(elem); 416 // } 417 // 418 // private static void resetStyle(Element elem) { 419 // final Node n = elem.getNode(); 420 // if (n.getScene() == null) { 421 // //System.out.println("RESET, not yet in scene, returning" + n); //NOI18N 422 // return; 423 // } 424 // resetStyle(n); 425 // } 426 // 427 //// private static void clearAuthorStyleSheets(Parent parent) { 428 //// for(String css : parent.getStylesheets()){ 429 //// try{ 430 //// removeStyleClasses(parent, new URL(css)); 431 //// } catch (MalformedURLException ex) { 432 //// Utils.println("Cannot remove style classes", ex); //NOI18N 433 //// } 434 //// } 435 //// parent.getStylesheets().clear(); 436 //// } 437 // 438 //// public static void loadAuthorCssFiles(Frame frame) { 439 //// Parent contentParent = getParent(frame); 440 //// final Project project = frame.getProject(); 441 //// try { 442 //// clearAuthorStyleSheets(contentParent); 443 //// for (Css css : project.getScreenData().getAuthorCss()) { 444 //// if (css.isActive()) { 445 //// URL u = css.getFile().toURI().toURL(); 446 //// loadAuthorCss(frame, contentParent, u); 447 //// } 448 //// } 449 //// } catch (Exception ex) { 450 //// frame.printWarning("messagebar.cannot.load.css.files", ex); 451 //// } 452 //// } 453 // 454 // private static Set<String> getStyleClasses(final URL url) throws Exception { 455 // Set<String> styleClasses = new HashSet<>(); 456 // Stylesheet s; 457 // try { 458 // s = new CssParser().parse(url); 459 // } catch (IOException ex) { 460 // Utils.println("Invalid Stylesheet " + url); 461 // return styleClasses; 462 // } 463 // if (s == null) { 464 // // The parsed CSS file was empty. No parsing occured. 465 // return styleClasses; 466 // } 467 // for (Rule r : s.getRules()) { 468 // for (Selector ss : r.getSelectors()) { 469 // if (ss instanceof SimpleSelector) { 470 // SimpleSelector simple = (SimpleSelector) ss; 471 // styleClasses.addAll(simple.getStyleClasses()); 472 // } else { 473 // if (ss instanceof CompoundSelector) { 474 // CompoundSelector cs = (CompoundSelector) ss; 475 // for (Selector selector : cs.getSelectors()) { 476 // if (selector instanceof SimpleSelector) { 477 // SimpleSelector simple = (SimpleSelector) selector; 478 // styleClasses.addAll(simple.getStyleClasses()); 479 // } 480 // } 481 // } 482 // } 483 // } 484 // } 485 // return styleClasses; 486 // } 487 // 488 // /* 489 // * Returns the CSS property value defined by the specified style class in the style sheet. 490 // * If the specifed style class is used in more than one rule, then the first one is returned. 491 // */ 492 // public static ParsedValue<?, ?> getValueFor(Stylesheet stylesheet, String styleClass, String property) { 493 // Rule rule = null; 494 // for (Rule r : stylesheet.getRules()) { 495 // for (Selector selector : r.getSelectors()) { 496 // // Simple selector 497 // if (selector instanceof SimpleSelector) { 498 // SimpleSelector simpleSelector = (SimpleSelector) selector; 499 // // Does the selector contain the style class 500 // if (simpleSelector.getStyleClasses() != null && simpleSelector.getStyleClasses().contains(styleClass)) { 501 // rule = r; 502 // break; 503 // } 504 // } // Compound selector 505 // else if (selector instanceof CompoundSelector) { 506 // CompoundSelector compoundSelector = (CompoundSelector) selector; 507 // for (SimpleSelector simpleSelector : compoundSelector.getSelectors()) { 508 // // Does the selector contain the style class 509 // if (simpleSelector.getStyleClasses() != null && simpleSelector.getStyleClasses().contains(styleClass)) { 510 // rule = r; 511 // break; 512 // } 513 // } 514 // } else { 515 // // Should not occur 516 // throw new IllegalArgumentException("Unsupported !!!!"); //NOI18N 517 // } 518 // } 519 // } 520 // if (rule != null) { 521 // for (Declaration decl : rule.getDeclarations()) { 522 // if (property.equals(decl.getProperty())) { 523 // return decl.getParsedValue(); 524 // } 525 // } 526 // } 527 // return null; 528 // } 529 // 530 // /** 531 // * When a visual is dragged, we want it to be contained in a StageViewContent container 532 // * Doing so, it complies with the style of the dropped content. 533 // * @param visual 534 // * @return The wrapped visual in a StageViewContent 535 // */ 536 // public static Node styleDragVisual(Frame frame, Node visual) { 537 // // Re-create the CSS context of the Scene. 538 // Group fakeScene = new Group(); 539 // // XXX @see DTL-4761, styling is much more than that. 540 // // We need to take into concideration drop targets (if we want to) 541 //// Parent p = getParent(frame); 542 //// fakeScene.getStylesheets().setAll(p.getStylesheets()); 543 // 544 // fakeScene.getChildren().add(visual); 545 // return fakeScene; 546 // } 547 // 548 // private static Parent getParent(Frame frame){ 549 // return frame.getStageView().getBackstagePane().getScenePreviewGroup(); 550 // } 551 // 552 // private static final class ContextMenuListener implements ChangeListener<ContextMenu> { 553 // private final Node node; 554 // 555 // public ContextMenuListener(Node node) { 556 // this.node = node; 557 // } 558 // 559 // @Override 560 // public void changed(ObservableValue<? extends ContextMenu> arg0, ContextMenu oldValue, ContextMenu newValue) { 561 // if (newValue != null) { 562 // arg0.removeListener(this); 563 // styleStyleable(node, newValue); 564 // } 565 // } 566 // } 567 // 568 // 569 // private static final class SubObjectsVisitor implements ComponentPathEventHandler { 570 // 571 // private final Node node; 572 // private final Scene scene; 573 // private boolean seenNonVisibleRoot; 574 // private int insideNonVisibleNumLevels; 575 // 576 // SubObjectsVisitor(Node node) { 577 // this.node = node; 578 // this.scene = node.getScene(); 579 // assert scene != null; 580 // } 581 // 582 // @Override 583 // public Visit push(ComponentReference ref) { 584 // // Do not visit nodes that are in the scene graph except for 585 // // the child of Skinnable (eg: TabPane) 586 // // This occurs when visiting indexed childs located in the scene graph. 587 // // These childs are root of visit so style their non visibles. 588 // if (ref.getChildComponent() instanceof Node && ref.getChildComponent() != node) { 589 // Node n = (Node) ref.getChildComponent(); 590 // if (n.getScene() != null) { 591 // return Visit.SKIP; 592 // } 593 // } 594 // if (ref.getChildComponent() instanceof PopupControl 595 // || ref.getChildComponent() instanceof Menu) { 596 // seenNonVisibleRoot = true; 597 // } 598 // if (seenNonVisibleRoot) { 599 // insideNonVisibleNumLevels += 1; 600 // styleObject(node, ref); 601 // } 602 // return Visit.DESCEND; 603 // } 604 // 605 // @Override 606 // public void pop() { 607 // if (insideNonVisibleNumLevels > 0) { 608 // insideNonVisibleNumLevels -= 1; 609 // } 610 // if (insideNonVisibleNumLevels == 0) { 611 // seenNonVisibleRoot = false; 612 // } 613 // } 614 // } 615 // 616 // /** 617 // * MAIN ENTRY POINT FOR CSS RESET/APPLICATION/ERROR HANDING 618 // * 619 // * @param project 620 // * @param e 621 // */ 622 // public static void applyCss(final Project project, final Element e) { 623 // // Project or Parent can be null for unit tests 624 // if (project == null || e.getNode().getParent() == null) { 625 // return; 626 // } 627 // 628 // // Make synchronous call to processCSS to be done outside critical path. 629 // // It has to be deferred, otherwise it interferes with wrap in SplitPane 630 // // Start to listen in the same tick, CSS can resolve lookup in a tick 631 // // running in between now and the following runLater. 632 // startListeningToCssErrors(); 633 // Platform.runLater(new Runnable() { 634 // 635 // @Override 636 // public void run() { 637 // doApplyCss(project, e); 638 // } 639 // }); 640 // } 641 // 642 // @CoverageCritical 643 // private static void doApplyCss(final Project project, final Element e) { 644 // try { 645 // /* 646 // * CSS is applied synchronously. This is required for error 647 // * tracking. Otherwise we can't differentiate possible CSS errors 648 // * fired by the SB css from User css. 649 // */ 650 // resetCssState(e); 651 // final Scene scene = e.getNode().getScene(); 652 // if (scene != null) { 653 // Deprecation.processCSS(e.getNode(), true); 654 // } 655 // boolean projectDisplayed = project.isProjectDisplayed(); 656 // // Visit the remaining paths to find menu/tooltip/... 657 // if (!projectDisplayed) { 658 // // Do nothing: there will be a call to refreshCSS when the 659 // // project root is added to the scenegraph. 660 // } else { 661 // if (e.getNode() instanceof Skinnable) { 662 // final Skinnable skinnable = (Skinnable) e.getNode(); 663 // if (skinnable.getSkin() == null) { 664 // assert false; 665 // } 666 // } 667 // if (scene == null) { 668 // // It ONLY happen for a node located inside a Custom Menu Item/ Tooltip,... We need the following logic. 669 // // At load time, for Nodes that would be located inside a skin not yet set (eg: content of a Tab, SplitPane). 670 // // The lookup is done but no styling occurs. 671 // List<ComponentPath> paths = project.lookupComponentPath(e.getNode()); 672 // for (ComponentPath p : paths) { 673 // Node inSceneNode = getDeepestInSceneNode(p); 674 // for (ComponentReference ref : p.getPath()) { 675 // if (styleObject(inSceneNode, ref)) { 676 // break; 677 // } 678 // } 679 // } 680 // } else { 681 // SubObjectsVisitor visitor = new SubObjectsVisitor(e.getNode()); 682 // ComponentReference ref = new ComponentIndexedReference(null, e.getNode()); 683 // Utils.visit(ref, visitor); 684 // } 685 // } 686 // } catch (Throwable thr) { 687 // Utils.println(thr.getMessage(), thr); 688 // } finally { 689 // stopListeningToCssErrors(); 690 // } 691 // } 692 // 693 public static Node getFirstAncestorWithNonNullScene(Node node) { 694 Node ancestor = node; 695 while ((ancestor != null) && (ancestor.getScene() == null)) { 696 ancestor = ancestor.getParent(); 697 } 698 699 return ancestor; 700 } 701 702 // static Node getDeepestInSceneNode(ComponentPath path) { 703 // Node inSceneNode = null; 704 // // Lookup the deepest node in the scene. 705 // for (ComponentReference ref : path.getPath()) { 706 // if (ref.getChildComponent() instanceof Node) { 707 // Node current = (Node) ref.getChildComponent(); 708 // if (current.getScene() == null) { 709 // // Stop. 710 // break; 711 // } else { 712 // inSceneNode = current; 713 // } 714 // } 715 // } 716 // assert inSceneNode.getScene() != null; 717 // return inSceneNode; 718 // } 719 // 720 // private static boolean styleObject(final Node node, final ComponentReference ref) { 721 // try { 722 // Object obj = ref.getChildComponent(); 723 // Styleable styleable = obj instanceof Styleable ? (Styleable)obj : null; 724 // if (styleable != null) { 725 // // Can be null for Menu. 726 // if ( Deprecation.getNode(styleable) != null) { 727 // styleStyleable(node, styleable); 728 // return true; 729 // } else { // Workaround for Null node in MenuItem. 730 // if (ref.getChildComponent() instanceof MenuItem) { 731 // final MenuItem mi = (MenuItem) ref.getChildComponent(); 732 // PopupControl pc = mi.getParentPopup(); 733 // 734 // if (pc != null) { // can be null for Menu. 735 // styleStyleable(node, pc); 736 // return true; 737 // } else { 738 // mi.parentPopupProperty().addListener(new ContextMenuListener(node)); 739 // } 740 // } 741 // } 742 // } 743 // } catch (Throwable thr) { 744 // Utils.println("Exception styling " + ref, thr); //NOI18N 745 // } 746 // return false; 747 // } 748 // Workaround null node for MenuItem and Tab. 749 public static Node getNode(Object target) { 750 if (target instanceof Node) { 751 return (Node) target; 752 } 753 Styleable styleable = (target instanceof Styleable) ? (Styleable) target : null; 754 Node node = null; 755 if (styleable != null) { 756 node = Deprecation.getNode(styleable); 757 if (node == null) { 758 if (target instanceof MenuItem) { 759 final MenuItem mi = (MenuItem) target; 760 PopupControl pc = mi.getParentPopup(); 761 762 if (pc != null) { // can be null for Menu. 763 node = Deprecation.getNode(pc); 764 } 765 } else { 766 if (target instanceof Tab) { 767 // Access the Skin Node 768 Tab tab = (Tab) target; 769 TabPane tp = tab.getTabPane(); 770 Set<Node> tabs = tp.lookupAll(".tab"); //NOI18N 771 for (Node n : tabs) { 772 Tab result = (Tab) n.getProperties().get(Tab.class); 773 assert result != null; 774 if (result == tab) { 775 node = n; 776 break; 777 } 778 } 779 } 780 } 781 } 782 } 783 return node; 784 } 785 786 // private static Styleable getStyleable(Object object) { 787 // if(object instanceof Styleable){ 788 // return (Styleable) object; 789 // } 790 // return null; 791 // } 792 // 793 // private static void styleStyleable(Node ownerNode, Styleable styleable) { 794 // Scene scene = ownerNode.getScene(); 795 // assert ownerNode.getScene() != null; 796 // Parent parentNode = ownerNode.getParent(); 797 // styleStyleable(parentNode, styleable); 798 // } 799 // 800 // private static void styleStyleable(Parent parent, Styleable control) { 801 // Node node = Deprecation.getNode(control); 802 // if(node == null) { 803 // return; 804 // } 805 // 806 // trackNode(node); 807 // double current = node.getOpacity(); 808 // node.setOpacity(0); 809 // assert node != null; 810 // try { 811 // addToParent(parent, node); 812 // Deprecation.processCSS(node, true); 813 // } finally { 814 // removeFromParent(parent, node); 815 // node.setOpacity(current); 816 // } 817 // } 818 static void addToParent(Parent p, Node node) { 819 if (p instanceof Group) { 820 ((Group) p).getChildren().add(node); 821 } else { 822 if (p instanceof Pane) { 823 ((Pane) p).getChildren().add(node); 824 } 825 } 826 } 827 828 static void removeFromParent(Parent p, Node node) { 829 if (p instanceof Group) { 830 ((Group) p).getChildren().remove(node); 831 } else { 832 if (p instanceof Pane) { 833 ((Pane) p).getChildren().remove(node); 834 } 835 } 836 } 837 838 // public static boolean needPageRefresh(Prop property) { 839 // return CSS_IMPACT.contains(property) || Prop.isTooltip(property) || Prop.isContextMenu(property); 840 // } 841 // 842 // private static class CssParsingListener implements ListChangeListener<CssError> { 843 // @Override 844 // public void onChanged(Change<? extends CssError> change) { 845 // // This is fired by unwanted CSS application (FX RT or ContentView/D&D/Handles/... 846 // if(!CSS_ADVERTISE) { 847 // return; 848 // } 849 // while (change.next()) { 850 // if (change.wasAdded()) { 851 // for(CssError error : change.getAddedSubList()){ 852 // Project proj; 853 // Scene scene = error.getScene(); 854 // if(scene == null) { 855 // // We have a single case where we asked for error and receive a null scene, this is the 856 // // loading time case. The parsing is done before the project is associated 857 // // to any Frame (@see lookupImagesInCssFile). 858 // if(LOADING_PROJECT == null){ 859 // assert Utils.isRunningUnitTests(); 860 // continue; 861 // } 862 // proj = LOADING_PROJECT; 863 // } else { 864 // Frame frame = Frame.get(scene); 865 // if(frame == null) { 866 // assert Utils.isRunningUnitTests(); 867 // } 868 // if(frame == null){ 869 // Utils.println("No Frame to route CSS error " + error.getMessage());//NOI18N 870 // continue; 871 // } 872 // proj = frame.getProject();; 873 // } 874 // final Project project = proj; 875 // assert project != null; 876 // if(project == null){ 877 // Utils.println("No Project to route CSS error " + error.getMessage());//NOI18N 878 // continue; 879 // } 880 // 881 // // CSS file added by user 882 // if(error instanceof StylesheetParsingError){ 883 // StylesheetParsingError serror = (StylesheetParsingError) error; 884 // URL url = serror.getURL(); 885 // if(url == null){ 886 // Utils.println("No URL for Stylesheet CSS error " + error.getMessage());//NOI18N 887 // continue; 888 // } 889 // String strURL = url.toExternalForm(); 890 // if(strURL.contains("com/oracle/javafx/authoring/css_stylesheets")){//NOI18N 891 // Utils.println("Error in SceneBuilder CSS " + error.getMessage());//NOI18N 892 // continue; 893 // } 894 // printMessage(project, serror); 895 // } else { 896 // if(error instanceof PropertySetError){// Semantic error, eg: invalid value type, unresolved lookup 897 // PropertySetError perror = (PropertySetError) error; 898 // Styleable faultyNode = perror.getStyleable(); 899 // List<ComponentPath> cp = project.lookupComponentPath(faultyNode); 900 // if(cp.isEmpty()){ 901 // if(isSkinSubPart(project, faultyNode)){ 902 // printMessage(project, error); 903 // } else { 904 // // The node is not in the ContentView, this is a SceneBuilder CSS error. 905 // Utils.println("Error in SceneBuilder CSS " + error.getMessage());//NOI18N 906 // continue; 907 // } 908 // } else { 909 // printMessage(project, error); 910 // } 911 // } else { 912 // if(error instanceof InlineStyleParsingError){ 913 // printMessage(project, error); 914 // } else { 915 // // Untyped CssError 916 // printMessage(project, error); 917 // } 918 // } 919 // } 920 // } 921 // } 922 // } 923 // } 924 // } 925 // // Go up until we findout at least one ComponentPath 926 // private static boolean isSkinSubPart(Project project, Styleable styleable){ 927 // Styleable parent = styleable.getStyleableParent(); 928 // 929 // if (parent == null) { 930 // return false; 931 // } 932 // 933 // while (parent != null) { 934 // List<ComponentPath> cp = project.lookupComponentPath(parent); 935 // if (!cp.isEmpty()) { 936 // return true; 937 // } 938 // parent = parent.getStyleableParent(); 939 // } 940 // 941 // return false; 942 // } 943 // 944 // private static class CssInlineStyleListener implements ListChangeListener<CssError> { 945 // 946 // List<CssError> errors = Utils.newList(); 947 // 948 // @Override 949 // public void onChanged(ListChangeListener.Change<? extends CssError> change) { 950 // StringBuilder builder = null; 951 // while (change.next()) { 952 // if (change.wasAdded()) { 953 // if (builder == null) { 954 // builder = new StringBuilder(); 955 // } 956 // for (CssError error : change.getAddedSubList()) { 957 // if (error instanceof InlineStyleParsingError) { 958 // errors.add(error); 959 // } 960 // } 961 // } 962 // } 963 // } 964 // 965 // private List<CssError> getErrors() { 966 // return errors; 967 // } 968 // } 969 // 970 // private static void printMessage(final Project project, final CssError error) { 971 // printMessage(project, error.getMessage()); 972 // } 973 // 974 // private static void printMessage(final Project project, final StylesheetParsingError error) { 975 // URL url = error.getURL(); 976 // String fileName = url.toExternalForm(); 977 // if(fileName.toLowerCase().startsWith("file:")){//NOI18N 978 // fileName = new File(fileName).getName(); 979 // } 980 // printMessage(project, fileName + " " + error.getMessage()); //NOI18N 981 // } 982 // 983 // private static void printMessage(final Project project, final String message) { 984 // if (Utils.isRunningUnitTests()) { 985 // Utils.printWarning(project, message); 986 // } else { 987 // Platform.runLater(new Runnable() { 988 // @Override 989 // public void run() { 990 // Utils.printWarning(project, message); 991 // } 992 // }); 993 // } 994 // } 995 // 996 // private static Project LOADING_PROJECT; 997 // private static boolean CSS_ADVERTISE; 998 // public static void startListeningToCssErrors() { 999 // CSS_ADVERTISE = true; 1000 // } 1001 // 1002 // public static void stopListeningToCssErrors() { 1003 // CSS_ADVERTISE = false; 1004 // } 1005 // 1006 // // Should be private, used by unit tests 1007 // static void startListeningToCssErrors(Project project) { 1008 // startListeningToCssErrors(); 1009 // Frame frame = Frame.get(project); 1010 // if (frame == null) { // Loading the project 1011 // LOADING_PROJECT = project; 1012 // } else { 1013 // CssError.setCurrentScene(frame.getScene()); 1014 // } 1015 // } 1016 // 1017 // // Should be private, used by unit tests 1018 // static void stopListeningToCssErrors(Project proj) { 1019 // stopListeningToCssErrors(); 1020 // LOADING_PROJECT = null; 1021 // CssError.setCurrentScene(null); 1022 // } 1023 // 1024 // private static final CssParsingListener cssListener = new CssParsingListener(); 1025 // static { 1026 // CssParser.errorsProperty().addListener(cssListener); 1027 // } 1028 // 1029 // public static void updateStylesheets(Project project, Parent parent, File file) { 1030 // startListeningToCssErrors(); 1031 // try { 1032 // 1033 // // This is done outside any transaction. 1034 // // replace the file that has been updated. And only this file. 1035 // // Replacing the whole list fires unwanted file parsing. 1036 // for(int i = 0; i < parent.getStylesheets().size(); i++){ 1037 // String url = parent.getStylesheets().get(i); 1038 // if(url.toLowerCase().startsWith("file:")){//NOI18N 1039 // File f; 1040 // try { 1041 // f = new File(new URL(url).toURI()); 1042 // } catch (Exception ex) { 1043 // Utils.println(ex.toString(), ex); 1044 // continue; 1045 // } 1046 // if(file.equals(f)){ 1047 // parent.getStylesheets().remove(url); 1048 // parent.getStylesheets().add(i, url); 1049 // } 1050 // } 1051 // } 1052 // // Force CSS to apply in order to have check for validity of the stylesheets content. 1053 // Deprecation.processCSS(parent, true); 1054 // } finally { 1055 // stopListeningToCssErrors(); 1056 // } 1057 // } 1058 // 1059 // public static void loadAuthorCssFiles(Frame frame) { 1060 // Parent contentParent = getParent(frame); 1061 // // Add the root styleclass, no side effect if not in used. 1062 // contentParent.getStyleClass().setAll(ROOT_STYLECLASS); 1063 // clearFrame(frame); 1064 // final Project project = frame.getProject(); 1065 // try { 1066 // Set<String> allImgs = Utils.newSet(); 1067 // for (File file : project.getScreenData().getAuthorCss()) { 1068 // URL u = file.toURI().toURL(); 1069 // loadAuthorCss(frame, contentParent, u); 1070 // Set<String> imgs = lookupImagesInCssFile(frame.getProject(), u.toURI(), false); 1071 // if (imgs != null) { 1072 // allImgs.addAll(imgs); 1073 // } 1074 // } 1075 // frame.getProject().getWatcher().addCssImages(contentParent, allImgs); 1076 // 1077 // } catch (Exception ex) { 1078 // frame.printWarning("messagebar.cannot.load.css.files", ex); 1079 // } 1080 // } 1081 // 1082 // public static void close(Frame frame) { 1083 // // Happens in unit tests. 1084 // if(frame.getStageView() == null || 1085 // frame.getStageView().getBackstagePane() == null){ 1086 // return; 1087 // } 1088 // clearFrame(frame); 1089 // } 1090 // private static void clearFrame(Frame frame){ 1091 // Parent parent = getParent(frame); 1092 // parent.getStylesheets().clear(); 1093 // STYLECLASSES_SETS.remove(parent); 1094 // frame.getProject().getWatcher().clearCssImages(parent); 1095 // } 1096 // 1097 // private static void loadAuthorCss(Frame frame, Parent parent, URL cssURL) throws Exception { 1098 // parent.getStylesheets().add(cssURL.toExternalForm()); 1099 // Set<String> styleClasses = getStyleClasses(cssURL); 1100 // List<StyleClasses> lst = STYLECLASSES_SETS.get(parent); 1101 // if (lst == null) { 1102 // lst = new ArrayList<>(); 1103 // STYLECLASSES_SETS.put(parent, lst); 1104 // } 1105 // StyleClasses sc = new StyleClasses(); 1106 // sc.url = cssURL.toExternalForm(); 1107 // sc.styleClasses = styleClasses; 1108 // lst.add(sc); 1109 // } 1110 // 1111 // public static Set<String> retrieveStyleClasses(Frame frame, ComponentPath path) { 1112 // List<StyleClasses> ret = STYLECLASSES_SETS.get(getParent(frame)); 1113 // Set<String> fullSet = new HashSet<>(); 1114 // if (ret != null) { 1115 // for (StyleClasses sc : ret) { 1116 // fullSet.addAll(sc.styleClasses); 1117 // } 1118 // } 1119 // // Compute stylesheets attached to the parent chain. 1120 // ComponentPath truncated = path.getNearestParentNodePath(); 1121 // for (ComponentReference ref : truncated.getPath()) { 1122 // if (ref.getChildComponent() instanceof Parent) { 1123 // Parent p = (Parent) ref.getChildComponent(); 1124 // for (String ss : p.getStylesheets()) { 1125 // try { 1126 // Set<String> classes = getStyleClasses(new URL(ss)); 1127 // fullSet.addAll(classes); 1128 // } catch (Exception ex) { 1129 // Utils.println("Can't parse Stylesheet " + ex); //NOI18N 1130 // } 1131 // } 1132 // } 1133 // } 1134 // return fullSet; 1135 // } 1136 // 1137 // public static Set<String> retrieveAlternateStyleClasses(Class<?> type){ 1138 // Set<String> alternates = ALTERNATE_STYLECLASSES.get(type); 1139 // Set<String> fullSet = new HashSet<>(); 1140 // if(alternates != null){ 1141 // fullSet.addAll(alternates); 1142 // } 1143 // return fullSet; 1144 // } 1145 // 1146 // public static boolean checkStyle(final Project project, String style) { 1147 // if (style == null || style.equals("")) { //NOI18N 1148 // return true; 1149 // } 1150 // Stylesheet s = null; 1151 // // Synchronous listener to get errors synchronously. 1152 // // Required for synchronous validation 1153 // CssInlineStyleListener listener = new CssInlineStyleListener(); 1154 // CssParser.errorsProperty().addListener(listener); 1155 // startListeningToCssErrors(project); 1156 // try { 1157 // try { 1158 // s = new CssParser().parseInlineStyle(new StyleableStub(style)); 1159 // }catch(final RuntimeException ex){ 1160 // // Parser exception that has not been tracked by the listener. 1161 // // Bug in CSS RT 1162 // Utils.println("Unexpected error parsing CSS style", ex); //NOI18N 1163 // } 1164 // } finally { 1165 // stopListeningToCssErrors(project); 1166 // CssParser.errorsProperty().removeListener(listener); 1167 // } 1168 // 1169 // return s != null && listener.getErrors().isEmpty(); 1170 // } 1171 // 1172 // public static void addStyleSheet(Frame frame){ 1173 // FileChooserWrapper fileChooser = FileChooserWrapper.create(). 1174 // extensionFilters(SS_EXTENSIONS). 1175 // title(Utils.getI18N().getString("window.title.add.style.sheet")).build(); 1176 // File f = fileChooser.showOpenDialog(frame.getStage()); 1177 // if(f!= null){ 1178 // Project p = frame.getProject(); 1179 // List<File> files = p.getStylesheets(); 1180 // if(!files.contains(f)){ 1181 // List<File> newLst = Utils.newList(); 1182 // newLst.addAll(files); 1183 // newLst.add(f); 1184 // p.setStylesheets(newLst); 1185 // } 1186 // } 1187 // } 1188 // 1189 // public static void removeStyleSheet(Frame frame, File f) { 1190 // assert f != null; 1191 // Project p = frame.getProject(); 1192 // List<File> files = p.getStylesheets(); 1193 // List<File> newLst = Utils.newList(); 1194 // newLst.addAll(files); 1195 // newLst.remove(f); 1196 // p.setStylesheets(newLst); 1197 // } 1198 // 1199 // private static final Set<String> IMG_PROPERTIES = Utils.newSet(); 1200 // static { 1201 // // String 1202 // IMG_PROPERTIES.add("-fx-image");//NOI18N 1203 // // String 1204 // IMG_PROPERTIES.add("-fx-graphic");//NOI18N 1205 // // String[] 1206 // IMG_PROPERTIES.add("-fx-background-image");//NOI18N 1207 // // String[] 1208 // IMG_PROPERTIES.add("-fx-border-image-source");//NOI18N 1209 // } 1210 // 1211 // private static class StyleableStub implements Styleable { 1212 // private final String style; 1213 // private StyleableStub(String style){ 1214 // this.style = style; 1215 // } 1216 // @Override 1217 // public String getTypeSelector() { 1218 // return null; 1219 // } 1220 // 1221 // @Override 1222 // public String getId() { 1223 // return null; 1224 // } 1225 // 1226 // @Override 1227 // public ObservableList<String> getStyleClass() { 1228 // return new SimpleListProperty<>(); 1229 // } 1230 // 1231 // @Override 1232 // public String getStyle() { 1233 // return style; 1234 // } 1235 // 1236 // @Override 1237 // public Styleable getStyleableParent() { 1238 // return null; 1239 // } 1240 // 1241 // @Override 1242 // @SuppressWarnings("rawtypes") 1243 // public List<CssMetaData<? extends Styleable, ?>> getCssMetaData() { 1244 // return Collections.emptyList(); 1245 // } 1246 // 1247 // @Override 1248 // public ObservableSet<PseudoClass> getPseudoClassStates() { 1249 // return null; // TODO Return something useful 1250 // } 1251 // } 1252 // 1253 // public static Set<String> lookupImagesInStyle(String style) { 1254 // if (style != null) { 1255 // try { 1256 // Stylesheet s = new CssParser().parseInlineStyle(new StyleableStub(style)); 1257 // return lookupImagesInStylesheet(s); 1258 // } catch (RuntimeException ex) { 1259 // Utils.println(ex.getMessage()); 1260 // } 1261 // } 1262 // return null; 1263 // } 1264 // 1265 // public static Set<String> lookupImagesInCssFile(Project project, URI uri, boolean isRemoval) { 1266 // if (uri != null) { 1267 // if (!isRemoval) { 1268 // startListeningToCssErrors(project); 1269 // } 1270 // try { 1271 // Stylesheet s = new CssParser().parse(uri.toURL()); 1272 // return lookupImagesInStylesheet(s); 1273 // } catch (Exception ex) { 1274 // Utils.println(ex.getMessage()); 1275 // } finally { 1276 // if (!isRemoval) { 1277 // stopListeningToCssErrors(project); 1278 // } 1279 // } 1280 // } 1281 // return null; 1282 // } 1283 // 1284 // private static Set<String> lookupImagesInStylesheet(Stylesheet s) { 1285 // Set<String> files = Utils.newSet(); 1286 // try { 1287 // for (Rule r : s.getRules()) { 1288 // for (Declaration d : r.getDeclarations()) { 1289 // if (IMG_PROPERTIES.contains(d.getProperty())) { 1290 // Object obj = d.getParsedValue().convert(null); 1291 // if (obj instanceof String) { 1292 // try { 1293 // files.add((String) obj); 1294 // } catch (Exception ex) { 1295 // Utils.println((String) obj, ex); 1296 // } 1297 // } else { 1298 // if (obj instanceof String[]) { 1299 // String[] array = (String[]) obj; 1300 // for (String a : array) { 1301 // try { 1302 // files.add(a); 1303 // } catch (Exception ex) { 1304 // Utils.println(a, ex); 1305 // } 1306 // } 1307 // } else { 1308 // Utils.println("Unknown type for CSS Img value " + obj);//NOI18N 1309 // } 1310 // } 1311 // } 1312 // } 1313 // } 1314 // } catch (RuntimeException ex) { 1315 // Utils.println(ex.getMessage());//NOI18N 1316 // } 1317 // return files; 1318 // } 1319 // 1320 // public static void workaroundForRT23223(Node node) { 1321 // if (Utils.IS_WINDOWS_XP) { 1322 // node.getStyleClass().add(CssUtils.SCENE_BUILDER_WINXP_FONT_STYLECLASS); 1323 // } else { 1324 // if(Utils.IS_WINDOWS){ 1325 // node.getStyleClass().add(CssUtils.SCENE_BUILDER_WIN_FONT_STYLECLASS); 1326 // } // else fallback on platform font size. 1327 // } 1328 // } 1329 // 1330 // // Only applies to Windows 7 and Vista, XP keep its 11px menu. 1331 // public static void workaroundForRT19435(MenuItem menu){ 1332 // if (Utils.IS_WINDOWS_7 || Utils.IS_WINDOWS_VISTA) { 1333 // menu.setStyle("-fx-font-size: 1.083em;");//NOI18N 1334 // } 1335 // } 1336 // 1337 // 1338 // /** 1339 // * Returns the first stylable node above the specified node inside the 1340 // * specified component. 1341 // * For now, this routine returns the node itself except when it is a Skin 1342 // * node : in that case, the routine the associated skinnable node. 1343 // */ 1344 // public static Node findEnclosingStylableNode(ComponentPath pickedPath, Node pickedNode) { 1345 // final Node result; 1346 // 1347 // assert pickedPath != null; 1348 // assert pickedNode != null; 1349 // 1350 // if ((pickedNode == pickedPath.getTargetChild()) || (pickedNode instanceof Skin)) { 1351 // // pickedNode matches the component or the Skin node 1352 // result = null; 1353 // } else { 1354 // result = pickedNode; 1355 // } 1356 // 1357 // return result; 1358 // } 1359 1360 public static Object getSceneGraphObject(Object selectedObject) { 1361 if (selectedObject instanceof FXOMObject) { 1362 return ((FXOMObject) selectedObject).getSceneGraphObject(); 1363 } else { 1364 return selectedObject; 1365 } 1366 } 1367 1368 public static Node getSelectedNode(Object selectedObject) { 1369 return CssUtils.getNode(CssUtils.getSceneGraphObject(selectedObject)); 1370 } 1371 1372 }