| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.sis.style.se1; |
| |
| import java.awt.Color; |
| import java.util.Arrays; |
| import java.util.Objects; |
| import jakarta.xml.bind.annotation.XmlTransient; |
| import org.opengis.util.InternationalString; |
| |
| // Specific to the main branch: |
| import org.apache.sis.filter.Expression; |
| |
| |
| /** |
| * Base class of all style objects. |
| * This base class cannot be extended directly. |
| * Instead, one of the subclasses can be extended. |
| * |
| * @author Martin Desruisseaux (Geomatys) |
| * |
| * @param <R> the type of data to style, such as {@code Feature} or {@code Coverage}. |
| */ |
| @XmlTransient |
| public abstract class StyleElement<R> implements Cloneable { |
| /** |
| * The factory to use for creating expressions and child elements. |
| * This is typically the same factory as the one used for creating this element. |
| * |
| * @see FeatureTypeStyle#FACTORY |
| * @see CoverageStyle#FACTORY |
| */ |
| protected final StyleFactory<R> factory; |
| |
| /** |
| * Creates a new style element. |
| * Intentionally restricted to this package because {@link #properties()} is package-private. |
| * |
| * @param factory the factory to use for creating expressions and child elements. |
| */ |
| StyleElement(final StyleFactory<R> factory) { |
| this.factory = Objects.requireNonNull(factory); |
| } |
| |
| /** |
| * Creates a shallow copy of the given object. |
| * For a deep copy, see {@link #clone()} instead. |
| * |
| * @param source the object to copy. |
| */ |
| StyleElement(final StyleElement<R> source) { |
| factory = source.factory; |
| } |
| |
| /** |
| * Creates a style element for XML unmarshalling. |
| * <em>This constructor is unsafe</em> and should be used only by JAXB reflection. |
| * |
| * @todo Allow the factory to be set according the parent {@link AbstractStyle} being unmarshalled. |
| * We will need to use {@link ThreadLocal}. |
| */ |
| StyleElement() { |
| factory = null; // TODO |
| } |
| |
| /** |
| * Returns a literal for the given value. |
| * This is a convenience method for use with setter methods that expect an expression. |
| * |
| * @param <E> type of value. |
| * @param value the value for which to return a literal, or {@code null} if none. |
| * @return literal for the given value, or {@code null} if the given value was null. |
| */ |
| public final <E> Expression<R,E> literal(final E value) { |
| return (value == null) ? null : factory.filterFactory.literal(value); |
| } |
| |
| /** |
| * Returns the given expression if non-null, or literal {@code true} otherwise. |
| * This is a convenience method for the implementation of getter methods when |
| * a default value exists. |
| * |
| * @param value the value for which to apply a default value if {@code null}. |
| * @return the given value if non-null, or {@code true} literal otherwise. |
| */ |
| protected final Expression<R,Boolean> defaultToTrue(final Expression<R,Boolean> value) { |
| return (value != null) ? value : factory.enabled; |
| } |
| |
| /** |
| * Returns the given expression if non-null, or literal {@code false} otherwise. |
| * This is a convenience method for the implementation of getter methods when |
| * a default value exists. |
| * |
| * @param value the value for which to apply a default value if {@code null}. |
| * @return the given value if non-null, or a {@code false} literal otherwise. |
| */ |
| protected final Expression<R,Boolean> defaultToFalse(final Expression<R,Boolean> value) { |
| return (value != null) ? value : factory.disabled; |
| } |
| |
| /** |
| * Returns the given expression if non-null, or literal {@code 0.0} otherwise. |
| * This is a convenience method for the implementation of getter methods when |
| * a default value exists. |
| * |
| * @param value the value for which to apply a default value if {@code null}. |
| * @return the given value if non-null, or {@code 0.0} literal otherwise. |
| */ |
| protected final Expression<R, ? extends Number> defaultToZero(final Expression<R, ? extends Number> value) { |
| return (value != null) ? value : factory.zero; |
| } |
| |
| /** |
| * Returns the given expression if non-null, or literal {@code 0.5} otherwise. |
| * This is a convenience method for the implementation of getter methods when |
| * a default value exists. |
| * |
| * @param value the value for which to apply a default value if {@code null}. |
| * @return the given value if non-null, or {@code 0.5} literal otherwise. |
| */ |
| protected final Expression<R, ? extends Number> defaultToHalf(final Expression<R, ? extends Number> value) { |
| return (value != null) ? value : factory.half; |
| } |
| |
| /** |
| * Returns the given expression if non-null, or literal {@code 1.0} otherwise. |
| * This is a convenience method for the implementation of getter methods when |
| * a default value exists. |
| * |
| * @param value the value for which to apply a default value if {@code null}. |
| * @return the given value if non-null, or {@code 1.0} literal otherwise. |
| */ |
| protected final Expression<R, ? extends Number> defaultToOne(final Expression<R, ? extends Number> value) { |
| return (value != null) ? value : factory.one; |
| } |
| |
| /** |
| * Returns the opacity of the alpha value of the given color. |
| * If the color is totally opaque, then this method returns {@code null}. |
| * |
| * @param color color from which to get the opacity. |
| * @return opacity derived from the alpha value of the color, or {@code null} if totally opaque. |
| */ |
| final Expression<R, ? extends Number> opacity(final Color color) { |
| final int alpha = color.getAlpha(); |
| return (alpha != 255) ? literal(alpha / 256d) : null; |
| // Divide by 256 instead of 255 in order to get round numbers for alpha values 64, 128, etc. |
| } |
| |
| /** |
| * Returns all properties contained in the subclasses. |
| * This is used for {@link #equals(Object)} and {@link #hashCode()} implementations. |
| * |
| * @return all properties. |
| */ |
| abstract Object[] properties(); |
| |
| /** |
| * Returns a hash code value for this object. |
| * |
| * @return a hash code value for this object. |
| */ |
| @Override |
| public int hashCode() { |
| return getClass().hashCode() + Arrays.hashCode(properties()); |
| } |
| |
| /** |
| * Compares this element with the given object for equality. |
| * |
| * @param obj the other object to compare with this. |
| * @return whether the other object is equal to this. |
| */ |
| @Override |
| public boolean equals(final Object obj) { |
| if (obj == this) { |
| return true; |
| } |
| return (obj != null) && (obj.getClass() == getClass()) && |
| Arrays.equals(properties(), ((StyleElement) obj).properties()); |
| } |
| |
| /** |
| * Returns a deep clone of this object. All style elements are cloned, |
| * but expressions are not on the assumption that they are immutable. |
| * ISO 19115 metadata and {@link InternationalString} members, if any, |
| * are not cloned neither in current Apache SIS version. |
| * |
| * @return a clone of this element. |
| */ |
| @Override |
| @SuppressWarnings("unchecked") |
| public StyleElement<R> clone() { |
| try { |
| return (StyleElement<R>) super.clone(); |
| } catch (CloneNotSupportedException e) { |
| throw new AssertionError(e); // Should never happen since we are cloneable. |
| } |
| } |
| } |