Spec-Zone .ru
спецификации, руководства, описания, API
001/*
002 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.  Oracle designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Oracle in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
022 * or visit www.oracle.com if you need additional information or have any
023 * questions.
024 */
025
026package javafx.css;
027
028import java.util.Collections;
029import java.util.List;
030import javafx.scene.Node;
031
032/**
033 * A CssMetaData instance provides information about the CSS style and
034 * provides the hooks that allow CSS to set a property value. 
035 * It encapsulates the CSS property name, the type into which the CSS value 
036 * is converted, and the default value of the property. 
037 * <p>
038 * CssMetaData is the bridge between a value that can be represented 
039 * syntactically in a .css file, and a {@link StyleableProperty}. There is 
040 * a one-to-one correspondence between a CssMetaData and a StyleableProperty.
041 * Typically, the CssMetaData of a will include the CssMetaData of its ancestors. 
042 * During CSS processing, the CSS engine iterates over the Node's CssMetaData, 
043 * looks up the parsed value of each, converts the parsed value, and 
044 * sets the value on the StyleableProperty. 
045 * <p>
046 * The method {@link Node#getCssMetaData()} is called to obtain the 
047 * List&lt;CssMetaData&gt;. This method is called frequently and it is prudent
048 * to return a static list rather than creating the list on each call. By 
049 * convention, node classes that have CssMetaData will implement a
050 * static method {@code getClassCssMetaData()} and it is customary to have
051 * {@code getCssMetaData()} simply return {@code getClassCssMetaData()}. The
052 * purpose of {@code getClassCssMetaData()} is to allow sub-classes to easily
053 * include the CssMetaData of some ancestor.
054 * <p>
055 * This example is a typical implementation. 
056 * <code><pre>
057 * private DoubleProperty gapProperty = new StyleableDoubleProperty(0) {
058 *     {@literal @}Override 
059 *      public CssMetaData{@literal <}MyWidget,Number{@literal >} getCssMetaData() {
060 *          return GAP_META_DATA;
061 *      }
062 *
063 *      {@literal @}Override
064 *      public Object getBean() {
065 *          return MyWidget.this;
066 *      }
067 *
068 *      {@literal @}Override
069 *      public String getName() {
070 *          return "gap";
071 *      }
072 * };
073 * 
074 * private static final CssMetaData GAP_META_DATA = 
075 *     new CssMetaData{@literal <}MyWidget,Number{@literal >}("-my-gap", StyleConverter.getSizeConverter(), 0d) {
076 * 
077 *        {@literal @}Override
078 *        public boolean isSettable(MyWidget node) {
079 *            return node.gapProperty == null || !node.gapProperty.isBound();
080 *        }
081 *    
082 *        {@literal @}Override
083 *        public StyleableProperty{@literal <}Number{@literal >} getStyleableProperty(MyWidget node) {
084 *            return (StyleableProperty{@literal <}Number{@literal >})node.gapProperty;
085 *        }
086 * };
087 * 
088 * private static final List{@literal <}CssMetaData{@literal <}? extends Node, ?{@literal >}{@literal >} cssMetaDataList; 
089 * static {
090 *     List{@literal <}CssMetaData{@literal <}? extends Node, ?{@literal >}{@literal >} temp =
091 *         new ArrayList{@literal <}CssMetaData{@literal <}? extends Node, ?{@literal >}{@literal >}(Control.getClassCssMetaData());
092 *     temp.add(GAP_META_DATA);
093 *     cssMetaDataList = Collections.unmodifiableList(temp);
094 * }
095 * 
096 * public static List{@literal <}CssMetaData{@literal <}? extends Node, ?{@literal >}{@literal >} getClassCssMetaData() {
097 *     return cssMetaDataList;
098 * }
099 * 
100 * {@literal @}Override
101 * public List{@literal <}CssMetaData{@literal <}? extends Node, ?{@literal >}{@literal >} getCssMetaData() {
102 *     return getClassCssMetaData();
103 * }
104 * </pre><code>
105 * @param <S> The type of Styleable
106 * @param <V> The type into which the parsed value is converted. 
107 */
108public abstract class CssMetaData<S extends Styleable, V> {
109    
110    /**
111     * Set the value of the corresponding property on the given Node.
112     * @param styleable The Styleable on which the property value is being set
113     * @param value The value to which the property is set
114     * @deprecated This method is no longer called from CSS code. 
115     * Use {@link StyleableProperty#applyStyle(javafx.css.StyleOrigin, java.lang.Object)}
116     */
117    @Deprecated
118    public void set(S styleable, V value, StyleOrigin origin) {
119        
120        final StyleableProperty<V> styleableProperty = getStyleableProperty(styleable);
121        final StyleOrigin currentOrigin = styleableProperty.getStyleOrigin();  
122        final V currentValue = styleableProperty.getValue();
123        
124        // RT-21185: Only apply the style if something has changed. 
125        if ((currentOrigin != origin)
126            || (currentValue != null 
127                ? currentValue.equals(value) == false 
128                : value != null)) {
129            
130            styleableProperty.applyStyle(origin, value);
131            
132        }
133    }
134
135    /**
136     * Check to see if the corresponding property on the given Node is
137     * settable. This method is called before any styles are looked up for the
138     * given property. It is abstract so that the code can check if the property 
139     * is settable without expanding the property. Generally, the property is 
140     * settable if it is not null or is not bound. 
141     * 
142     * @param styleable The Styleable on which the property value is being set
143     * @return true if the property can be set.
144     */
145    public abstract boolean isSettable(S styleable);
146
147    /**
148     * Return the corresponding {@link StyleableProperty} for the given Node. 
149     * Note that calling this method will cause the property to be expanded. 
150     * @param styleable The Styleable for which the property is returned
151     * @return The StyleableProperty corresponding to this CssMetaData for the
152     * given Styleable
153     */
154    public abstract StyleableProperty<V> getStyleableProperty(S styleable);
155            
156    private final String property;
157    /**
158     * @return the CSS property name
159     */
160    public final String getProperty() {
161        return property;
162    }
163
164    private final StyleConverter<?,V> converter;
165    /**
166     * @return The CSS converter that handles conversion from a CSS value to a Java Object
167     */
168    public final StyleConverter<?,V> getConverter() {
169        return converter;
170    }
171
172    private final V initialValue;
173    /**
174     * The initial value of a CssMetaData corresponds to the default 
175     * value of the StyleableProperty in code. 
176     * For example, the default value of Shape.fill is Color.BLACK and the
177     * initialValue of Shape.StyleableProperties.FILL is also Color.BLACK.
178     * <p>
179     * There may be exceptions to this, however. The initialValue may depend
180     * on the state of the Node. A ScrollBar has a default orientation of 
181     * horizontal. If the ScrollBar is vertical, however, this method should
182     * return Orientation.VERTICAL. Otherwise, a vertical ScrollBar would be
183     * incorrectly set to a horizontal ScrollBar when the initial value is 
184     * applied.
185     * @return The initial value of the property, possibly null
186     */
187    public V getInitialValue(S styleable) {
188        return initialValue;
189    }
190    
191    private final List<CssMetaData<? extends Styleable, ?>> subProperties;
192    /**
193     * The sub-properties refers to the constituent properties of this property,
194     * if any. For example, "-fx-font-weight" is sub-property of "-fx-font".
195     */
196    public final List<CssMetaData<? extends Styleable, ?>> getSubProperties() {
197        return subProperties;
198    }
199
200    private final boolean inherits;
201    /**
202     * If true, the value of this property is the same as
203     * the parent's computed value of this property.
204     * @default false
205     * @see <a href="http://www.w3.org/TR/css3-cascade/#inheritance">CSS Inheritance</a>
206     */
207    public final boolean isInherits() {
208        return inherits;
209    }
210
211    /**
212     * Construct a CssMetaData with the given parameters and no sub-properties.
213     * @param property the CSS property
214     * @param converter the StyleConverter used to convert the CSS parsed value to a Java object.
215     * @param initalValue the CSS string 
216     * @param inherits true if this property uses CSS inheritance
217     * @param subProperties the sub-properties of this property. For example,
218     * the -fx-font property has the sub-properties -fx-font-family, 
219     * -fx-font-size, -fx-font-weight, and -fx-font-style.
220     */
221    protected CssMetaData(
222            final String property, 
223            final StyleConverter<?,V> converter, 
224            final V initialValue, 
225            boolean inherits, 
226            final List<CssMetaData<? extends Styleable, ?>> subProperties) {        
227        
228        this.property = property;
229        this.converter = converter;
230        this.initialValue = initialValue;
231        this.inherits = inherits;
232        this.subProperties = subProperties != null ? Collections.unmodifiableList(subProperties) : null;        
233        
234        if (this.property == null || this.converter == null) {
235            throw new IllegalArgumentException("neither property nor converter can be null");
236        }
237    }
238
239    /**
240     * Construct a CssMetaData with the given parameters and no sub-properties.
241     * @param property the CSS property
242     * @param converter the StyleConverter used to convert the CSS parsed value to a Java object.
243     * @param initalValue the CSS string 
244     * @param inherits true if this property uses CSS inheritance
245     */
246    protected CssMetaData(
247            final String property, 
248            final StyleConverter<?,V> converter, 
249            final V initialValue, 
250            boolean inherits) {
251        this(property, converter, initialValue, inherits, null);
252    }
253
254    /**
255     * Construct a CssMetaData with the given parameters, inherit set to
256     * false and no sub-properties.
257     * @param property the CSS property
258     * @param converter the StyleConverter used to convert the CSS parsed value to a Java object.
259     * @param initalValue the CSS string 
260     */
261    protected CssMetaData(
262            final String property, 
263            final StyleConverter<?,V> converter, 
264            final V initialValue) {
265        this(property, converter, initialValue, false, null);
266    }
267
268    /**
269     * Construct a CssMetaData with the given parameters, initialValue is
270     * null, inherit is set to false, and no sub-properties.
271     * @param property the CSS property
272     * @param converter the StyleConverter used to convert the CSS parsed value to a Java object.
273     * @param initalValue the CSS string 
274     */
275    protected CssMetaData(
276            final String property, 
277            final StyleConverter<?,V> converter) {
278        this(property, converter, null, false, null);
279    }
280
281    @Override
282    public boolean equals(Object obj) {
283        if (obj == null) {
284            return false;
285        }
286        if (getClass() != obj.getClass()) {
287            return false;
288        }
289        final CssMetaData<? extends Styleable, ?> other = (CssMetaData<? extends Styleable, ?>) obj;
290        if ((this.property == null) ? (other.property != null) : !this.property.equals(other.property)) {
291            return false;
292        }
293        return true;
294    }
295
296    @Override
297    public int hashCode() {
298        int hash = 3;
299        hash = 19 * hash + (this.property != null ? this.property.hashCode() : 0);
300        return hash;
301    }
302    
303    
304    @Override public String toString() {
305        return  new StringBuilder("CSSProperty {")
306            .append("property: ").append(property)
307            .append(", converter: ").append(converter.toString())
308            .append(", initalValue: ").append(String.valueOf(initialValue))
309            .append(", inherits: ").append(inherits)
310            .append(", subProperties: ").append(
311                (subProperties != null) ? subProperties.toString() : "[]")
312            .append("}").toString();
313    }
314
315
316}