/* * Copyright (c) 2012, 2015, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * * This file is available and licensed under the following license: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the distribution. * - Neither the name of Oracle Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.oracle.javafx.scenebuilder.kit.editor.panel.css; import com.oracle.javafx.scenebuilder.kit.editor.panel.css.CssContentMaker.CssPropertyState.CssStyle; import com.oracle.javafx.scenebuilder.kit.editor.panel.css.NodeCssState.CssProperty; import com.oracle.javafx.scenebuilder.kit.fxom.FXOMInstance; import com.oracle.javafx.scenebuilder.kit.fxom.FXOMObject; import com.oracle.javafx.scenebuilder.kit.metadata.Metadata; import com.oracle.javafx.scenebuilder.kit.metadata.property.PropertyMetadata; import com.oracle.javafx.scenebuilder.kit.metadata.property.ValuePropertyMetadata; import com.oracle.javafx.scenebuilder.kit.metadata.util.PropertyName; import com.oracle.javafx.scenebuilder.kit.util.CssInternal; import com.oracle.javafx.scenebuilder.kit.util.Deprecation; import javafx.css.Rule; import javafx.css.Style; import javafx.css.StyleOrigin; import java.net.MalformedURLException; import java.net.URL; import java.util.*; import javafx.css.CssMetaData; import javafx.css.ParsedValue; import javafx.css.StyleableProperty; import javafx.scene.Node; import javafx.scene.Parent; /** * This class construct the model exposed by the CSS Panel. * * @treatAsPrivate */ public class CssContentMaker { private CssContentMaker() { assert false; } /* * * Public methods * */ public static PropertyState initialValue(N n, CssMetaData sub) { PropertyState val = null; try { Object fxValue; String cssValue; Object value = sub.getInitialValue(n); if (value == null) { cssValue = "none";//NOI18N fxValue = cssValue; } else { fxValue = sub.getInitialValue(n); cssValue = CssValueConverter.toCssString(sub.getProperty(), n); } val = newInitialPropertyState(fxValue, cssValue, n, sub); } catch (RuntimeException ex) { System.out.println(ex.getMessage() + " " + ex); // Ok no initial value or InitialValue bug. } return val; } @SuppressWarnings("unchecked") public static PropertyState initialValue(N n, CssProperty complex, CssMetaData sub) { PropertyState val = null; try { Object fxValue; String cssValue; Object complexInitial = complex.getStyleable().getInitialValue(complex.getTarget()); if (complexInitial == null) { cssValue = "none";//NOI18N fxValue = cssValue; } else { fxValue = sub.getInitialValue(n); cssValue = CssValueConverter.toCssString(sub.getProperty(), complexInitial); } val = newInitialPropertyState(fxValue, cssValue, n, sub); } catch (RuntimeException ex) { System.out.println(ex.getMessage() + " " + ex); // Ok no initial value or InitialValue bug. } return val; } @SuppressWarnings("rawtypes") public static PropertyState modelValue(N node, CssMetaData cssMeta, FXOMObject fxomObject) { PropertyState val = null; if (fxomObject == null) { // In this case, we are handling a sub-component, no model value then. return null; } // First retrieve the java bean property and check if it is overriden by the inspector. String beanPropName = CssUtils.getBeanPropertyName(node, cssMeta); if (beanPropName == null) { // No corresponding java bean property return null; } PropertyName beanPropertyName = new PropertyName(beanPropName); assert fxomObject instanceof FXOMInstance; FXOMInstance fxomInstance = (FXOMInstance) fxomObject; ValuePropertyMetadata propMeta = Metadata.getMetadata().queryValueProperty(fxomInstance, beanPropertyName); if (propMeta == null) { // No corresponding metadata return null; } if (!propMeta.isReadWrite()) { // R/O : no overridden return null; } boolean overriden = false; Object defaultValue = propMeta.getDefaultValueObject(); Object propertyValue = propMeta.getValueObject(fxomInstance); if ((propertyValue == null) || (defaultValue == null)) { if (propertyValue != defaultValue) { overriden = true; } } else if (!propertyValue.equals(defaultValue)) { overriden = true; } if (overriden) { // We have an override. val = new BeanPropertyState(propMeta, cssMeta.getProperty(), propertyValue, CssValueConverter.toCssString(cssMeta.getProperty(), propertyValue)); // An overriden can have sub properties if (cssMeta.getSubProperties() != null && !cssMeta.getSubProperties().isEmpty()) { for (CssMetaData sub : cssMeta.getSubProperties()) { // Create a virtual sub property PropertyState subProp = new BeanPropertyState(propMeta, sub.getProperty(), propertyValue, CssValueConverter.toCssString(sub.getProperty(), propertyValue)); val.getSubProperties().add(subProp); } } } return val; } public static Node getSourceNodeForStyle(Object component, String property) { Node ret = null; Node n = CssUtils.getNode(component); if (n != null) { if (n.getStyle() != null && n.getStyle().contains(property)) { ret = n; } else { Parent p = n.getParent(); while (p != null) { String s = p.getStyle(); if (s != null && s.contains(property)) { ret = p; break; } p = p.getParent(); } } } return ret; } public static boolean isInlineInherited(Object component, CssPropertyState cssProperty) { boolean isInherited = false; Node node = CssUtils.getNode(component); if (node == null) { return false; } // Not located on this node, must be inherited then if (node.getStyle() == null) { return true; } if (!containsInStyle(cssProperty, node.getStyle())) { isInherited = true; } return isInherited; } public static boolean containsPseudoState(String selector) { return selector.contains(":");//NOI18N } /* * * Private methods * */ private static boolean containsInStyle(CssPropertyState prop, String style) { return style.contains(prop.getCssProperty()); } public static NodeCssState getCssState(Object selectedObject) { Node node = CssUtils.getSelectedNode(selectedObject); if (node == null) { return null; } Parent p = null; double current = 1; try { if (node.getScene() == null) { // The node is not visible (ContextMenu, Tooltip, ...) // A node MUST be in the scene to allow for CSS content collect, // so we add it (temporarily) to the scene. Node inScene = CssUtils.getFirstAncestorWithNonNullScene(node); if (inScene == null) { // May happen if the Content Panel is not present return null; } p = inScene.getParent(); current = node.getOpacity(); node.setOpacity(0); CssUtils.addToParent(p, node); } NodeCssState state = new NodeCssState(CssInternal.collectCssState(node), node, getFXOMObject(selectedObject)); return state; } finally { if (p != null) { CssUtils.removeFromParent(p, node); node.setOpacity(current); } } } private static FXOMObject getFXOMObject(Object selectedObject) { if (selectedObject instanceof FXOMObject) { return (FXOMObject) selectedObject; } else { return null; } } @SuppressWarnings("rawtypes") private static InitialPropertyState newInitialPropertyState( Object fxValue, String cssValue, N n, CssMetaData cssMeta) { InitialPropertyState val = new InitialPropertyState(cssMeta.getProperty(), fxValue, cssValue); if (cssMeta.getSubProperties() != null && !cssMeta.getSubProperties().isEmpty()) { for (CssMetaData sub : cssMeta.getSubProperties()) { Object subValue = CssValueConverter.getSubPropertyValue(sub.getProperty(), fxValue); String subCssValue = CssValueConverter.toCssString(subValue); PropertyState subProp = new InitialPropertyState(sub.getProperty(), subValue, subCssValue); val.getSubProperties().add(subProp); } } return val; } // Retrieve the styles associated to the value. This is the case of lookup (or variable) @SuppressWarnings("rawtypes") protected static CssStyle retrieveStyle(List