All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.nuiton.jaxx.compiler.css.StylesheetHelper Maven / Gradle / Ivy

The newest version!
/*
 * #%L
 * JAXX :: Compiler
 * %%
 * Copyright (C) 2008 - 2024 Code Lutin, Ultreia.io
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * #L%
 */

package org.nuiton.jaxx.compiler.css;

import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.nuiton.jaxx.compiler.CompiledObject;
import org.nuiton.jaxx.compiler.CompilerException;
import org.nuiton.jaxx.compiler.JAXXCompiler;
import org.nuiton.jaxx.compiler.binding.DataBinding;
import org.nuiton.jaxx.compiler.binding.DataBindingHelper;
import org.nuiton.jaxx.compiler.binding.PseudoClassDataBinding;
import org.nuiton.jaxx.compiler.css.parser.CSSParser;
import org.nuiton.jaxx.compiler.css.parser.CSSParserConstants;
import org.nuiton.jaxx.compiler.css.parser.CSSParserTreeConstants;
import org.nuiton.jaxx.compiler.css.parser.SimpleNode;
import org.nuiton.jaxx.compiler.reflect.ClassDescriptor;
import org.nuiton.jaxx.compiler.reflect.ClassDescriptorHelper;
import org.nuiton.jaxx.compiler.reflect.MethodDescriptor;
import org.nuiton.jaxx.compiler.tags.DefaultComponentHandler;
import org.nuiton.jaxx.compiler.tags.DefaultObjectHandler;
import org.nuiton.jaxx.compiler.tags.TagManager;
import org.nuiton.jaxx.compiler.tags.swing.TabWithValidatorHandler;
import org.nuiton.jaxx.compiler.types.TypeManager;
import org.nuiton.jaxx.runtime.css.Pseudoclasses;
import org.nuiton.jaxx.runtime.css.Rule;
import org.nuiton.jaxx.runtime.css.Selector;
import org.nuiton.jaxx.runtime.css.Stylesheet;

import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.net.URI;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * A helper class to compute {@link Stylesheet}, {@link Rule} and {@link Selector}
 * and extract all the compiler logic from this class.
 *
 * In that way we can make the compiler as a single module and a runtime as another module.
 *
 * @author Tony Chemit - [email protected]
 */
public class StylesheetHelper {

    /** Logger */
    static private final Logger log = LogManager.getLogger(StylesheetHelper.class);

    public static URL getStyleURL(String attrValue, File baseDirectory, ClassLoader classLoader) throws IOException {
        if (attrValue.startsWith("classpath:/")) {
            URL resource = classLoader.getResource(attrValue.substring("classpath:".length() + 1));
            if (resource == null) {
                throw new IOException("Style not found: " + attrValue);
            }
            return resource;
        }
        if (baseDirectory == null) {
            Path path = Paths.get(attrValue);
            return Files.exists(path) ? path.toUri().toURL() : URI.create(attrValue).toURL();
        }

        File styleFile = new File(baseDirectory, attrValue.replace('/', File.separatorChar));
        if (!styleFile.exists()) {
            throw new IOException("Style not found: " + attrValue);
        }
        return styleFile.toURI().toURL();

    }
    public static Stylesheet processStylesheet(String stylesheetText) throws CompilerException {
        CSSParser p = new CSSParser(new StringReader(stylesheetText));
        SimpleNode node;
        try {
            node = p.Stylesheet();
        } catch (Error e) {
            throw new CompilerException(e);
        }
        List rules = new ArrayList<>();
        for (int i = 0; i < node.jjtGetNumChildren(); i++) {
            SimpleNode ruleNode = node.getChild(i);
            Rule rule = processRule(ruleNode);
            rules.add(rule);
        }
        Stylesheet stylesheet;
        stylesheet = new Stylesheet(rules.toArray(new Rule[rules.size()]));
        return stylesheet;
    }

    public static Rule processRule(SimpleNode ruleNode) {
        if (ruleNode.getId() != CSSParserTreeConstants.JJTRULE) {
            throw new IllegalArgumentException("argument node is not a Rule");
        }
        SimpleNode selectorsNode = ruleNode.getChild(0);
        assert selectorsNode.getId() == CSSParserTreeConstants.JJTSELECTORS :
                "expected node to be of type Selectors";

        List selectors = new ArrayList<>();
        for (int i = 0; i < selectorsNode.jjtGetNumChildren(); i++) {
            SimpleNode selectorNode = selectorsNode.getChild(i);
            selectors.add(processSelector(selectorNode));
        }

        Map properties = new HashMap<>();
        for (int i = 1; i < ruleNode.jjtGetNumChildren(); i++) {
            SimpleNode declarationNode = ruleNode.getChild(i);
            if (declarationNode.getId() == CSSParserTreeConstants.JJTDECLARATION) {
                String key = declarationNode.getChild(0).getText();
                SimpleNode valueNode = declarationNode.getChild(1);
                String value = valueNode.getText();
                if (valueNode.firstToken.kind == CSSParserConstants.STRING) {
                    value = value.substring(1, value.length() - 1);
                }
                properties.put(key, value);
            }
        }
        Rule rule;
        rule = new Rule(selectors.toArray(
                new Selector[selectors.size()]), properties);
        return rule;
    }

    public static Selector processSelector(SimpleNode selector) {
        if (selector.getId() != CSSParserTreeConstants.JJTSELECTOR) {
            throw new IllegalArgumentException("argument node is not a Selector");
        }
        String javaClassName = null;
        String styleClass = null;
        String pseudoClass = null;
        String id = null;

        for (int i = 0; i < selector.jjtGetNumChildren(); i++) {
            SimpleNode child = selector.getChild(i);
            switch (child.getId()) {
                case CSSParserTreeConstants.JJTJAVACLASS:
                    if (!child.getText().trim().equals("*")) {
                        javaClassName = child.getText();
                    }
                    break;
                case CSSParserTreeConstants.JJTCLASS:
                    styleClass = child.getText().substring(1);
                    break;
                case CSSParserTreeConstants.JJTPSEUDOCLASS:
                    pseudoClass = child.getText().substring(1);
                    break;
                case CSSParserTreeConstants.JJTID:
                    id = child.getText().substring(1);
                    break;

                default:
                    throw new IllegalStateException(
                            "unexpected child of Selector node, type=" +
                                    child.getId());
            }
        }

        return new Selector(javaClassName, styleClass, pseudoClass, id);
    }

    public enum MouseEventEnum {

        mouseover("mouseEntered", "mouseExited"),
        mouseout("mouseExited", "mouseReleased"),
        mousedown("mousePressed", "mousePressed"),
        mouseup("mouseReleased", "mousePressed");

        final String addMethod;

        final String removeMethod;

//        ClassDescriptor mouseListenerDescriptor;
//        ClassDescriptor mouseEventDescriptor;

        MouseEventEnum(String addMethod, String removeMethod) {
            this.removeMethod = removeMethod;
            this.addMethod = addMethod;
        }

        public String getProperty(int i) {
            return i == 0 ? addMethod : removeMethod;
        }
    }

    static ClassDescriptor mouseListenerDescriptor;

    static ClassDescriptor mouseEventDescriptor;

    public static ClassDescriptor getMouseEventDescriptor() {
        if (mouseEventDescriptor == null) {
            mouseEventDescriptor =
                    ClassDescriptorHelper.getClassDescriptor(MouseEvent.class);
        }
        return mouseEventDescriptor;
    }

    public static ClassDescriptor getMouseListenerDescriptor() {
        if (mouseListenerDescriptor == null) {
            mouseListenerDescriptor =
                    ClassDescriptorHelper.getClassDescriptor(MouseListener.class);
        }
        return mouseListenerDescriptor;
    }

    public static MethodDescriptor getAddMouseListenerMethod(CompiledObject object) {
        try {
            return object.getObjectClass().getMethodDescriptor(
                    "addMouseListener",
                    getMouseListenerDescriptor()
            );
        } catch (NoSuchMethodException e) {
            throw new CompilerException(
                    "could not find addMouseListener for object " + object);
        }
    }

    public static MethodDescriptor getMouseListenerMethod(CompiledObject object, String property) {
        try {
            return getMouseListenerDescriptor().getMethodDescriptor(
                    property,
                    getMouseEventDescriptor()
            );
        } catch (NoSuchMethodException e) {
            throw new CompilerException(
                    "could not find " + property + " for object " + object);
        }
    }

    public static void applyTo(CompiledObject object,
                               JAXXCompiler compiler,
                               Stylesheet stylesheet,
                               Stylesheet overrides) throws CompilerException {
        Map overriddenProperties;
        if (overrides != null) {
            overriddenProperties = getApplicableProperties(overrides, object);
            //overriddenProperties = overrides.getApplicableProperties(s,object);
        } else {
            overriddenProperties = null;
        }

        Map properties = getApplicableProperties(stylesheet,
                                                                 object);
        if (properties != null) {
            if (overriddenProperties != null) {
                properties.keySet().removeAll(overriddenProperties.keySet());
            }
            DefaultObjectHandler handler = TagManager.getTagHandler(object.getObjectClass());
            if (properties.containsKey(DefaultComponentHandler.I18N_PROPERTY_ATTRIBUTE)) {
                String key = DefaultComponentHandler.I18N_PROPERTY_ATTRIBUTE;
                String value = properties.get(key);
                if (handler instanceof DefaultComponentHandler)
                    handler.setAttribute(object, key, value, false, compiler);
                else if (handler instanceof TabWithValidatorHandler)
                    handler.setAttribute(object, key, value, false, compiler);
                else {
                    handler.setAttributeFromCss(object, key, value, compiler);
                }
            }
            for (Map.Entry e : properties.entrySet()) {
                String value = e.getValue();
                if (value.equals(Rule.INLINE_ATTRIBUTE) || value.equals(Rule.DATA_BINDING)) {
                    continue;
                }
                if (e.getKey().equals(DefaultComponentHandler.I18N_PROPERTY_ATTRIBUTE)) {
                    continue;
                }

                if (handler instanceof DefaultComponentHandler)
                    handler.setAttribute(object, e.getKey(), e.getValue(), false, compiler);
                else if (handler instanceof TabWithValidatorHandler)
                    handler.setAttribute(object, e.getKey(), e.getValue(), false, compiler);
                else {
                    handler.setAttributeFromCss(object, e.getKey(), value, compiler);
                }
            }
        }

        Rule[] pseudoClasses = getApplicablePseudoClasses(stylesheet, object);
        if (pseudoClasses != null) {
            Map> combinedPseudoClasses =
                    new LinkedHashMap<>();
            for (Rule pseudoClass1 : pseudoClasses) {
                Selector[] selectors = pseudoClass1.getSelectors();
                for (Selector selector : selectors) {
                    if (appliesTo(selector, object) ==
                            Selector.PSEUDOCLASS_APPLIES) {
                        properties = pseudoClass1.getProperties();
                        String pseudoClass = selector.getPseudoClass();
                        // TODO: overrides by downstream pseudoclasses are not handled
                        Map combinedProperties =
                                combinedPseudoClasses.computeIfAbsent(pseudoClass, k -> new HashMap<>());
                        combinedProperties.putAll(properties);
                    }
                }
            }

            int count = 0;
            for (Map.Entry> e :
                    combinedPseudoClasses.entrySet()) {
                applyPseudoClass(e.getKey(), e.getValue(), object, compiler,
                                 count++);
            }
        }
    }

    public static String unwrap(ClassDescriptor type, String valueCode) {
        if (ClassDescriptorHelper.getClassDescriptor(boolean.class).equals(type)) {
            return "((Boolean) " + valueCode + ").booleanValue()";
        }
        if (ClassDescriptorHelper.getClassDescriptor(byte.class).equals(type)) {
            return "((Byte) " + valueCode + ").byteValue()";
        }
        if (ClassDescriptorHelper.getClassDescriptor(short.class).equals(type)) {
            return "((Short) " + valueCode + ").shortValue()";
        }
        if (ClassDescriptorHelper.getClassDescriptor(int.class).equals(type)) {
            return "((Integer) " + valueCode + ").intValue()";
        }
        if (ClassDescriptorHelper.getClassDescriptor(long.class).equals(type)) {
            return "((Long) " + valueCode + ").longValue()";
        }
        if (ClassDescriptorHelper.getClassDescriptor(float.class).equals(type)) {
            return "((Float) " + valueCode + ").floatValue()";
        }
        if (ClassDescriptorHelper.getClassDescriptor(double.class).equals(type)) {
            return "((Double) " + valueCode + ").doubleValue()";
        }
        if (ClassDescriptorHelper.getClassDescriptor(char.class).equals(type)) {
            return "((Character) " + valueCode + ").charValue()";
        }
        return valueCode;
    }

    public enum PseudoClassEnum {
        focused("{ object.hasFocus() }"),
        unfocused("{ !object.hasFocus() }"),
        enabled("{ object.isEnabled() }"),
        disabled("{ !object.isEnabled() }"),
        selected("{ object.isSelected() }"),
        deselected("{ !object.isSelected() }");

        final String code;

        PseudoClassEnum(String code) {
            this.code = code;
        }

        public String getCode() {
            return code;
        }
    }

    public static void applyPseudoClass(String pseudoClass,
                                        Map properties,
                                        CompiledObject object,
                                        JAXXCompiler compiler,
                                        int priority) throws CompilerException {
        if (pseudoClass.contains("[")) {
            pseudoClass = pseudoClass.substring(0, pseudoClass.indexOf("["));
        }
        StringBuilder buffer = new StringBuilder();

        DefaultObjectHandler handler =
                TagManager.getTagHandler(object.getObjectClass());
        boolean valueDeclared = false;
        String eol = JAXXCompiler.getLineSeparator();
        DataBindingHelper bindingHelper = compiler.getBindingHelper();

        String pseudoClassesPrefix = null;
        String dataBindingPrefix = null;

        if (!properties.isEmpty()) {
            pseudoClassesPrefix = compiler.getImportedType(Pseudoclasses.class);
            dataBindingPrefix = compiler.getImportedType(org.nuiton.jaxx.runtime.css.DataBinding.class);
        }

        String outputClassName =
                compiler.getImportedType(compiler.getOutputClassName());

        for (Map.Entry e : properties.entrySet()) {
            String property = e.getKey();
            ClassDescriptor type = handler.getPropertyType(object,
                                                           property,
                                                           compiler
            );
            if (log.isDebugEnabled()) {
                log.debug("will test if databinding : [" + e.getValue() +
                                  "] type=" + type);
            }
            String dataBindingCode = compiler.processDataBindings(e.getValue());
            String valueCode;
            String simpleType = compiler.getImportedType(JAXXCompiler.getCanonicalName(type));

            if (dataBindingCode != null) {
                String code = object.getId() + "." + property + "." + priority;
                valueCode = "new " + dataBindingPrefix + "(" +
                        TypeManager.getJavaCode(code) + ")";
                DataBinding binding = new DataBinding(
                        code,
                        dataBindingCode,
                        handler.getSetPropertyCode(
                                object.getJavaCode(),
                                property,
                                "(" + simpleType + ") " + dataBindingCode,
//                                "(" + JAXXCompiler.getCanonicalName(type) + ") " + dataBindingCode,
                                compiler
                        ),
                        false
                );
                bindingHelper.registerDataBinding(binding);
            } else {
                try {
                    Class typeClass = type != null ?
                            ClassDescriptorHelper.getClass(
                                    type.getName(),
                                    type.getClassLoader()
                            ) :
                            null;
                    valueCode = TypeManager.getJavaCode(
                            TypeManager.convertFromString(e.getValue(), typeClass)
                    );
                } catch (ClassNotFoundException ex) {
                    compiler.reportError(
                            "could not find class " + type.getName());
                    return;
                }
            }
            if (!valueDeclared) {
                buffer.append("Object ");
                valueDeclared = true;
            }

            buffer.append("value = ");
            buffer.append(pseudoClassesPrefix);
            buffer.append(".applyProperty(");
            buffer.append(outputClassName);
            buffer.append(".this, ");
            buffer.append(object.getJavaCode());
            buffer.append(", ");
            buffer.append(TypeManager.getJavaCode(property));
            buffer.append(", ");
            buffer.append(valueCode);
            buffer.append(", ");
            buffer.append(pseudoClassesPrefix);
            buffer.append(".wrap(");
            buffer.append(handler.getGetPropertyCode(object.getJavaCode(), property, compiler));
            buffer.append("), ");
            buffer.append(priority);
            buffer.append(");");
            buffer.append(eol);

            buffer.append("if (!(value instanceof ");
            buffer.append(dataBindingPrefix);
            buffer.append(")) {");
            buffer.append(eol);

            String unwrappedValue = unwrap(type, "value");
            buffer.append("    ");
            buffer.append(handler.getSetPropertyCode(object.getJavaCode(), property, "(" + simpleType + ") " + unwrappedValue, compiler));
            buffer.append(eol);
            buffer.append("}").append(eol);
        }

        try {
            PseudoClassEnum classEnum = PseudoClassEnum.valueOf(pseudoClass);
            pseudoClass = classEnum.getCode();
        } catch (IllegalArgumentException e) {
            // should never happens ?
//            throw new RuntimeException("could not find " + PseudoClassEnum.class + " with pseudoClass " + pseudoClass, e);
        }

        compilePseudoClass(pseudoClass, object, buffer.toString(), 0, "add", compiler, false);

        buffer.setLength(0);
        valueDeclared = false;
        for (Map.Entry e : properties.entrySet()) {
            String property = e.getKey();
            ClassDescriptor type = handler.getPropertyType(object, property, compiler);
            String simpleType = compiler.getImportedType(JAXXCompiler.getCanonicalName(type));
            if (log.isDebugEnabled()) {
                log.debug("will test if databinding : [" + e.getValue() + "] type=" + type);
            }
            String dataBindingCode = compiler.processDataBindings(e.getValue());
            String valueCode;
            if (dataBindingCode != null) {
                String code = object.getId() + "." + property + "." + priority;
                valueCode = "new " + dataBindingPrefix + "(" + TypeManager.getJavaCode(code) + ")";
                DataBinding binding = new DataBinding(
                        code,
                        dataBindingCode,
                        handler.getSetPropertyCode(
                                object.getJavaCode(),
                                property,
                                "(" + simpleType + ") " + dataBindingCode,
                                compiler
                        ),
                        false
                );
                bindingHelper.registerDataBinding(binding);
            } else {
                try {
                    Class typeClass =
                            type != null ?
                                    ClassDescriptorHelper.getClass(type.getName(), type.getClassLoader()) :
                                    null;
                    valueCode = TypeManager.getJavaCode(TypeManager.convertFromString(e.getValue(), typeClass));
                } catch (ClassNotFoundException ex) {
                    compiler.reportError("could not find class " + type.getName());
                    return;
                }
            }
            if (!valueDeclared) {
                buffer.append("Object ");
                valueDeclared = true;
            }
            buffer.append("value = ").append(pseudoClassesPrefix).append(".removeProperty(");

            buffer.append(outputClassName);
            buffer.append(".this, ");
            buffer.append(object.getJavaCode());
            buffer.append(", ");
            buffer.append(TypeManager.getJavaCode(property));
            buffer.append(", ");
            buffer.append(valueCode);
            buffer.append(", ").append(pseudoClassesPrefix).append(".wrap(");
            buffer.append(handler.getGetPropertyCode(object.getJavaCode(),
                                                     property,
                                                     compiler)
            );
            buffer.append("), ");
            buffer.append(priority);
            buffer.append(");");
            buffer.append(eol);

            buffer.append("if (!(value instanceof ");
            buffer.append(dataBindingPrefix);
            buffer.append(")) {");
            buffer.append(eol);

//            String simpleType = importManager.getType(JAXXCompiler.getCanonicalName(type));
            String unwrappedValue = unwrap(type, "value");
            buffer.append("    ");
            buffer.append(handler.getSetPropertyCode(
                    object.getJavaCode(),
                    property,
                    "(" + simpleType + ") " + unwrappedValue,
                    compiler)
            );
            buffer.append(eol);
            buffer.append("}").append(eol);
        }
        compilePseudoClass(pseudoClass,
                           object,
                           buffer.toString(),
                           1,
                           "remove",
                           compiler,
                           true
        );
    }


    public static void compilePseudoClass(String pseudoClass,
                                          CompiledObject object,
                                          String propertyCode,
                                          int pos,
                                          String methodName,
                                          JAXXCompiler compiler,
                                          boolean invertTest) throws CompilerException {

        PseudoClassDataBinding binding =
                PseudoClassDataBinding.newPseudoClassDataBinding(
                        pseudoClass,
                        object,
                        propertyCode,
                        methodName,
                        invertTest
                );
        if (binding != null) {
            compiler.getBindingHelper().registerDataBinding(binding);
            return;
        }
        MouseEventEnum constant = MouseEventEnum.valueOf(pseudoClass);
        String property = constant.getProperty(pos);
        MethodDescriptor addMouseListener = getAddMouseListenerMethod(object);
        MethodDescriptor methodDescriptor =
                getMouseListenerMethod(object, property);
        object.addEventHandler("style." + pseudoClass + "." + methodName,
                               addMouseListener,
                               methodDescriptor,
                               propertyCode,
                               compiler
        );
    }

    public static Map getApplicableProperties(
            Stylesheet s, CompiledObject object) throws CompilerException {
        DefaultObjectHandler handler =
                TagManager.getTagHandler(object.getObjectClass());
        Map result = null;
        for (Rule rule : s.getRules()) {
            int apply = appliesTo(rule, object);
            if (apply == Selector.ALWAYS_APPLIES ||
                    apply == Selector.ALWAYS_APPLIES_INHERIT_ONLY) {
                if (result == null) {
                    result = new HashMap<>();
                }
                for (Map.Entry entry :
                        rule.getProperties().entrySet()) {
                    String property = entry.getKey();
                    if (apply == Selector.ALWAYS_APPLIES || handler.isPropertyInherited(property)) {
                        String ruleValue = entry.getValue().replace("%%", object.getId());
                        result.put(property, ruleValue);
                    }
                }
            }
        }
        return result;
    }

    public static Rule[] getApplicablePseudoClasses(
            Stylesheet s, CompiledObject object) throws CompilerException {
        List result = null;
        for (Rule rule : s.getRules()) {
            if (appliesTo(rule, object) == Selector.PSEUDOCLASS_APPLIES) {
                if (result == null) {
                    result = new ArrayList<>();
                }
                result.add(rule);
            }
        }
        return result != null ? result.toArray(new Rule[result.size()]) : null;
    }

    public static Rule inlineAttribute(CompiledObject object,
                                       String propertyName,
                                       boolean dataBinding) {
        Map properties = new HashMap<>();
        properties.put(propertyName, dataBinding ?
                Rule.DATA_BINDING :
                Rule.INLINE_ATTRIBUTE);
        return new Rule(new Selector[]{
                new Selector(null, null, null, object.getId(), true)},
                        properties
        );
    }

    public static int appliesTo(Rule rule,
                                CompiledObject object) throws CompilerException {
        int appliesTo = Selector.NEVER_APPLIES;
        for (Selector selector : rule.getSelectors()) {
            appliesTo = Math.max(appliesTo(selector, object), appliesTo);
            if (appliesTo == Selector.ALWAYS_APPLIES ||
                    appliesTo == Selector.ALWAYS_APPLIES_INHERIT_ONLY) {
                break;
            }
        }
        return appliesTo;
    }

    public static int appliesTo(Selector selector, CompiledObject object) {
        boolean inheritOnly = false;
        CompiledObject parent = object;
        String javaClassName = selector.getJavaClassName();
        String styleClass = selector.getStyleClass();
        String pseudoClass = selector.getPseudoClass();
        String id = selector.getId();

        while (parent != null) {
            boolean classMatch = javaClassName == null;
            if (!classMatch) {
                ClassDescriptor javaClass = parent.getObjectClass();
                do {
                    String name = javaClass.getName();
                    if (name.equals(javaClassName) ||
                            name.substring(name.lastIndexOf(".") + 1).equals(javaClassName)) {
                        classMatch = true;
                        break;
                    }
                    javaClass = javaClass.getSuperclass();
                } while (javaClass != null);
            }

            boolean styleClassMatch = parent.matchStyleClass(styleClass);

            String objectId = parent.getId();
            objectId = objectId.substring(objectId.lastIndexOf(".") + 1);
            boolean idMatch = id == null ||
                    (' ' + objectId + ' ').contains(' ' + id + ' ');

            if (classMatch && styleClassMatch && idMatch) {
                if (pseudoClass != null) {
                    return inheritOnly ?
                            Selector.PSEUDOCLASS_APPLIES_INHERIT_ONLY :
                            Selector.PSEUDOCLASS_APPLIES;
                } else {
                    return inheritOnly ?
                            Selector.ALWAYS_APPLIES_INHERIT_ONLY :
                            Selector.ALWAYS_APPLIES;
                }
            }

            parent = parent.getParent();
            inheritOnly = true;
        }
        return Selector.NEVER_APPLIES;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy