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 = CSSParser.getInstance().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 = CSSParser.getInstance().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 //        StyleManager.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 //        StyleManager.errorsProperty().addListener(listener);
1155 //        startListeningToCssErrors(project);
1156 //        try {
1157 //            try {
1158 //                s = CSSParser.getInstance().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 //            StyleManager.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 = CSSParser.getInstance().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 = CSSParser.getInstance().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 }