/*
* Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javafx.css;
import javafx.css.converter.BooleanConverter;
import javafx.css.converter.ColorConverter;
import javafx.css.converter.DeriveColorConverter;
import javafx.css.converter.DeriveSizeConverter;
import javafx.css.converter.DurationConverter;
import javafx.css.converter.EffectConverter;
import javafx.css.converter.EnumConverter;
import javafx.css.converter.FontConverter;
import javafx.css.converter.InsetsConverter;
import javafx.css.converter.LadderConverter;
import javafx.css.converter.PaintConverter;
import javafx.css.converter.SizeConverter;
import javafx.css.converter.StopConverter;
import javafx.css.converter.StringConverter;
import javafx.css.converter.URLConverter;
import javafx.geometry.Insets;
import javafx.scene.effect.Effect;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.text.Font;
import javafx.util.Duration;
import com.sun.javafx.scene.layout.region.CornerRadiiConverter;
import com.sun.javafx.util.Logging;
import com.sun.javafx.logging.PlatformLogger;
import com.sun.javafx.logging.PlatformLogger.Level;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
StyleConverter converts ParsedValue<F,T>
from type F
to type T
. The CssMetaData
API requires a StyleConverter
which is used when computing a value for the StyleableProperty
. There are a number of predefined converters which are accessible by the static methods of this class. F
is the type of the parsed value and T
is the converted type of the ParsedValueImpl. For example, a converter from String to Color would be declared public Color convert(ParsedValueImpl<String,Color> value, Font font)
Type parameters: See Also: Since: JavaFX 8.0
/**
* StyleConverter converts {@code ParsedValue<F,T>}
* from type {@code F} to type {@code T}. The
* {@link CssMetaData} API requires a {@code StyleConverter} which is used
* when computing a value for the {@code StyleableProperty}. There are
* a number of predefined converters which are accessible by the static
* methods of this class.
*
* {@code F} is the type of the parsed value and {@code T} is the converted type of
* the ParsedValueImpl. For example, a converter from String to Color would
* be declared
* <p>
* {@code public Color convert(ParsedValueImpl<String,Color> value, Font font)}
* </p>
*
* @param <F> the type of the parsed value
* @param <T> the converted type of the ParsedValueImpl
*
* @see ParsedValue
* @see StyleableProperty
* @since JavaFX 8.0
*/
public class StyleConverter<F, T> {
Convert from the parsed CSS value to the target property type.
Params: - value – The
ParsedValue
to convert - font – The
Font
to use when converting a relative
value.
Returns: the converted target property type
/**
* Convert from the parsed CSS value to the target property type.
*
* @param value The {@link ParsedValue} to convert
* @param font The {@link Font} to use when converting a
* <a href="http://www.w3.org/TR/css3-values/#relative-lengths">relative</a>
* value.
* @return the converted target property type
*/
@SuppressWarnings("unchecked")
public T convert(ParsedValue<F,T> value, Font font) {
// unchecked!
return (T) value.getValue();
}
Return a StyleConverter
that converts "true" or "false" to Boolean
. See Also: Returns: A StyleConverter
that converts "true" or "false" to Boolean
/**
* Return a {@code StyleConverter} that converts {@literal "true" or "false"} to {@code Boolean}.
* @return A {@code StyleConverter} that converts {@literal "true" or "false"} to {@code Boolean}
* @see Boolean#valueOf(java.lang.String)
*/
public static StyleConverter<String,Boolean> getBooleanConverter() {
return BooleanConverter.getInstance();
}
Return a StyleConverter
that converts a String representation of a duration to a Duration
. Returns: A StyleConverter
that converts a String representation of a duration to a Duration
Since: JavaFX 8u40
/**
* Return a {@code StyleConverter} that converts a String representation of
* a duration to a {@link Duration}.
* @return A {@code StyleConverter} that converts a String
* representation of a duration to a {@link Duration}
*
* @since JavaFX 8u40
*/
public static StyleConverter<?,Duration> getDurationConverter() {
return DurationConverter.getInstance();
}
Return a StyleConverter
that converts a String representation of a web color to a Color
. See Also: Returns: A StyleConverter
that converts a String representation of a web color to a Color
/**
* Return a {@code StyleConverter} that converts a String representation of
* a web color to a {@code Color}.
* @return A {@code StyleConverter} that converts a String
* representation of a web color to a {@code Color}
* @see Color#web(java.lang.String)
*/
public static StyleConverter<String,Color> getColorConverter() {
return ColorConverter.getInstance();
}
Return a StyleConverter
that converts a parsed representation of an Effect
to an Effect
See Also: Returns: A StyleConverter
that converts a parsed representation of an Effect
to an Effect
/**
* Return a {@code StyleConverter} that converts a parsed representation
* of an {@code Effect} to an {@code Effect}
* @return A {@code StyleConverter} that converts a parsed representation
* of an {@code Effect} to an {@code Effect}
* @see Effect
*/
public static StyleConverter<ParsedValue[], Effect> getEffectConverter() {
return EffectConverter.getInstance();
}
Return a StyleConverter
that converts a String representation of an Enum
to an Enum
. Params: - enumClass – the enum Class
Type parameters: - <E> – the type of the
Enum
See Also: Returns: A StyleConverter
that converts a String representation of an Enum
to an Enum
/**
* Return a {@code StyleConverter} that converts a String representation
* of an {@code Enum} to an {@code Enum}.
* @param <E> the type of the {@code Enum}
* @param enumClass the enum Class
* @return A {@code StyleConverter} that converts a String representation
* of an {@code Enum} to an {@code Enum}
* @see Enum#valueOf(java.lang.Class, java.lang.String)
*/
public static <E extends Enum<E>> StyleConverter<String, E> getEnumConverter(Class<E> enumClass) {
// TODO: reuse EnumConverter instances
EnumConverter<E> converter;
converter = new EnumConverter<>(enumClass);
return converter;
}
Return a StyleConverter
that converts a parsed representation of a Font
to an Font
. See Also: Returns: A StyleConverter
that converts a parsed representation of a Font
to an Font
/**
* Return a {@code StyleConverter} that converts a parsed representation
* of a {@code Font} to an {@code Font}.
* @return A {@code StyleConverter} that converts a parsed representation
* of a {@code Font} to an {@code Font}
* @see Font#font(java.lang.String, javafx.scene.text.FontWeight, javafx.scene.text.FontPosture, double)
*/
public static StyleConverter<ParsedValue[], Font> getFontConverter() {
return FontConverter.getInstance();
}
Return a StyleConverter
that converts a [<length> |
<percentage>]{1,4} to an Insets
. Returns: A StyleConverter
that converts a [<length> |
<percentage>]{1,4} to an Insets
/**
* Return a {@code StyleConverter} that converts a {@literal [<length> |
* <percentage>]}{1,4} to an {@code Insets}.
* @return A {@code StyleConverter} that converts a {@literal [<length> |
* <percentage>]}{1,4} to an {@code Insets}
*/
public static StyleConverter<ParsedValue[], Insets> getInsetsConverter() {
return InsetsConverter.getInstance();
}
Return a StyleConverter
that converts a parsed representation of a Paint
to a Paint
. Returns: A StyleConverter
that converts a parsed representation of a Paint
to a Paint
/**
* Return a {@code StyleConverter} that converts a parsed representation
* of a {@code Paint} to a {@code Paint}.
* @return A {@code StyleConverter} that converts a parsed representation
* of a {@code Paint} to a {@code Paint}
*/
public static StyleConverter<ParsedValue<?, Paint>, Paint> getPaintConverter() {
return PaintConverter.getInstance();
}
CSS length and number values are parsed into a Size object that is converted to a Number before the value is applied. If the property is a Number
type other than Double
, the set method of (CssMetaData
can be overridden to convert the Number
to the correct type. For example, if the property is an IntegerProperty
: @Override public void set(MyNode node, Number value, Origin origin) { if (value != null) { super.set(node, value.intValue(), origin); } else { super.set(node, value, origin); } }
Returns: A StyleConverter
that converts a parsed representation of a CSS length or number value to a Number
that is an instance of Double
/**
* CSS length and number values are parsed into a Size object that is
* converted to a Number before the value is applied. If the property is
* a {@code Number} type other than {@code Double}, the set method
* of ({@code CssMetaData} can be overridden to convert the {@code Number}
* to the correct type. For example, if the property is an {@code IntegerProperty}:
* <pre><code>
* {@literal @}Override public void set(MyNode node, Number value, Origin origin) {
* if (value != null) {
* super.set(node, value.intValue(), origin);
* } else {
* super.set(node, value, origin);
* }
* }
* </code></pre>
* @return A {@code StyleConverter} that converts a parsed representation
* of a CSS length or number value to a {@code Number} that is an instance
* of {@code Double}
*/
public static StyleConverter<?, Number> getSizeConverter() {
return SizeConverter.getInstance();
}
A converter for quoted strings which may have embedded unicode characters.
Returns: A StyleConverter
that converts a representation of a CSS string value to a String
/**
* A converter for quoted strings which may have embedded unicode characters.
* @return A {@code StyleConverter} that converts a representation of a
* CSS string value to a {@code String}
*/
public static StyleConverter<String,String> getStringConverter() {
return StringConverter.getInstance();
}
A converter for URL strings.
Returns: A StyleConverter
that converts a representation of a CSS URL value to a String
/**
* A converter for URL strings.
* @return A {@code StyleConverter} that converts a representation of a
* CSS URL value to a {@code String}
*/
public static StyleConverter<ParsedValue[], String> getUrlConverter() {
return URLConverter.getInstance();
}
Convert from the constituent values to the target property type.
Implemented by Types that have Keys with subKeys.
Params: - convertedValues – the constituent values
Returns: the target property type Since: 9
/**
* Convert from the constituent values to the target property type.
* Implemented by Types that have Keys with subKeys.
*
* @param convertedValues the constituent values
* @return the target property type
* @since 9
*/
public T convert(Map<CssMetaData<? extends Styleable, ?>,Object> convertedValues) {
return null;
}
Write binary data.
Params: - os – the data output stream
- sstore – the string store
Throws: - IOException – the exception
Since: 9
/**
* Write binary data.
* @param os the data output stream
* @param sstore the string store
* @throws java.io.IOException the exception
* @since 9
*/
public void writeBinary(DataOutputStream os, StringStore sstore)
throws IOException {
String cname = getClass().getName();
int index = sstore.addString(cname);
os.writeShort(index);
}
private static Map<ParsedValue, Object> cache;
Clear the cache.
Since: 9
/**
* Clear the cache.
* @since 9
*/
public static void clearCache() {
if (cache != null) {
cache.clear();
}
}
Get the cached value for the specified key.
Params: - key – the key
Returns: the cached value Since: 9
/**
* Get the cached value for the specified key.
* @param key the key
* @return the cached value
* @since 9
*/
protected T getCachedValue(ParsedValue key) {
if (cache != null) {
return (T)cache.get(key);
}
return null;
}
Cache the value for the specified key.
Params: - key – the key
- value – the value
Since: 9
/**
* Cache the value for the specified key.
* @param key the key
* @param value the value
* @since 9
*/
protected void cacheValue(ParsedValue key, Object value) {
if (cache == null) cache = new WeakHashMap<>();
cache.put(key, value);
}
// map of StyleConverter class name to StyleConverter
private static Map<String,StyleConverter<?, ?>> tmap;
Read binary data stream.
Params: - is – the data input stream
- strings – the strings
Throws: - IOException – the exception
Returns: the style converter Since: 9
/**
* Read binary data stream.
* @param is the data input stream
* @param strings the strings
* @return the style converter
* @throws java.io.IOException the exception
* @since 9
*/
@SuppressWarnings("rawtypes")
public static StyleConverter<?,?> readBinary(DataInputStream is, String[] strings)
throws IOException {
int index = is.readShort();
String cname = strings[index];
if (cname == null || cname.isEmpty()) return null;
if (cname.startsWith("com.sun.javafx.css.converters.")) {
// JavaFX 9: converter classes were moved from
// com.sun.javafx.css.converters.* to javafx.css.converter.*
// Note: the word 'converters' has become 'converter'.
cname = "javafx.css.converter." + cname.substring("com.sun.javafx.css.converters.".length());
}
if (cname.startsWith("javafx.css.converter.EnumConverter")) {
return (StyleConverter)javafx.css.converter.EnumConverter.readBinary(is, strings);
}
// Make a new entry in tmap, if necessary
if (tmap == null || !tmap.containsKey(cname)) {
StyleConverter<?,?> converter = getInstance(cname);
if (converter == null) {
final PlatformLogger logger = Logging.getCSSLogger();
if (logger.isLoggable(Level.SEVERE)) {
logger.severe("could not deserialize " + cname);
}
}
if (converter == null) {
System.err.println("could not deserialize " + cname);
}
if (tmap == null) tmap = new HashMap<String,StyleConverter<?,?>>();
tmap.put(cname, converter);
return converter;
}
return tmap.get(cname);
}
// package for unit test purposes
static StyleConverter<?,?> getInstance(final String converterClass) {
StyleConverter<?,?> styleConverter = null;
switch(converterClass) {
case "javafx.css.converter.BooleanConverter" :
styleConverter = javafx.css.converter.BooleanConverter.getInstance();
break;
case "javafx.css.converter.ColorConverter" :
styleConverter = javafx.css.converter.ColorConverter.getInstance();
break;
case "javafx.css.converter.CursorConverter" :
styleConverter = javafx.css.converter.CursorConverter.getInstance();
break;
case "javafx.css.converter.EffectConverter" :
styleConverter = javafx.css.converter.EffectConverter.getInstance();
break;
case "javafx.css.converter.EffectConverter$DropShadowConverter" :
styleConverter = javafx.css.converter.EffectConverter.DropShadowConverter.getInstance();
break;
case "javafx.css.converter.EffectConverter$InnerShadowConverter" :
styleConverter = javafx.css.converter.EffectConverter.InnerShadowConverter.getInstance();
break;
case "javafx.css.converter.FontConverter" :
styleConverter = javafx.css.converter.FontConverter.getInstance();
break;
case "javafx.css.converter.FontConverter$FontStyleConverter" :
case "javafx.css.converter.FontConverter$StyleConverter" :
styleConverter = javafx.css.converter.FontConverter.FontStyleConverter.getInstance();
break;
case "javafx.css.converter.FontConverter$FontWeightConverter" :
case "javafx.css.converter.FontConverter$WeightConverter" :
styleConverter = javafx.css.converter.FontConverter.FontWeightConverter.getInstance();
break;
case "javafx.css.converter.FontConverter$FontSizeConverter" :
case "javafx.css.converter.FontConverter$SizeConverter" :
styleConverter = javafx.css.converter.FontConverter.FontSizeConverter.getInstance();
break;
case "javafx.css.converter.InsetsConverter" :
styleConverter = javafx.css.converter.InsetsConverter.getInstance();
break;
case "javafx.css.converter.InsetsConverter$SequenceConverter" :
styleConverter = javafx.css.converter.InsetsConverter.SequenceConverter.getInstance();
break;
case "javafx.css.converter.PaintConverter" :
styleConverter = javafx.css.converter.PaintConverter.getInstance();
break;
case "javafx.css.converter.PaintConverter$SequenceConverter" :
styleConverter = javafx.css.converter.PaintConverter.SequenceConverter.getInstance();
break;
case "javafx.css.converter.PaintConverter$LinearGradientConverter" :
styleConverter = javafx.css.converter.PaintConverter.LinearGradientConverter.getInstance();
break;
case "javafx.css.converter.PaintConverter$RadialGradientConverter" :
styleConverter = javafx.css.converter.PaintConverter.RadialGradientConverter.getInstance();
break;
case "javafx.css.converter.SizeConverter" :
styleConverter = javafx.css.converter.SizeConverter.getInstance();
break;
case "javafx.css.converter.SizeConverter$SequenceConverter" :
styleConverter = javafx.css.converter.SizeConverter.SequenceConverter.getInstance();
break;
case "javafx.css.converter.StringConverter" :
styleConverter = javafx.css.converter.StringConverter.getInstance();
break;
case "javafx.css.converter.StringConverter$SequenceConverter" :
styleConverter = javafx.css.converter.StringConverter.SequenceConverter.getInstance();
break;
case "javafx.css.converter.URLConverter" :
styleConverter = javafx.css.converter.URLConverter.getInstance();
break;
case "javafx.css.converter.URLConverter$SequenceConverter" :
styleConverter = javafx.css.converter.URLConverter.SequenceConverter.getInstance();
break;
// Region stuff - including 2.x class names
case "com.sun.javafx.scene.layout.region.BackgroundPositionConverter" :
case "com.sun.javafx.scene.layout.region.BackgroundImage$BackgroundPositionConverter" :
styleConverter = com.sun.javafx.scene.layout.region.BackgroundPositionConverter.getInstance();
break;
case "com.sun.javafx.scene.layout.region.BackgroundSizeConverter" :
case "com.sun.javafx.scene.layout.region.BackgroundImage$BackgroundSizeConverter" :
styleConverter = com.sun.javafx.scene.layout.region.BackgroundSizeConverter.getInstance();
break;
case "com.sun.javafx.scene.layout.region.BorderImageSliceConverter" :
case "com.sun.javafx.scene.layout.region.BorderImage$SliceConverter" :
styleConverter = com.sun.javafx.scene.layout.region.BorderImageSliceConverter.getInstance();
break;
case "com.sun.javafx.scene.layout.region.BorderImageWidthConverter" :
styleConverter = com.sun.javafx.scene.layout.region.BorderImageWidthConverter.getInstance();
break;
case "com.sun.javafx.scene.layout.region.BorderImageWidthsSequenceConverter" :
styleConverter = com.sun.javafx.scene.layout.region.BorderImageWidthsSequenceConverter.getInstance();
break;
case "com.sun.javafx.scene.layout.region.BorderStrokeStyleSequenceConverter" :
case "com.sun.javafx.scene.layout.region.StrokeBorder$BorderStyleSequenceConverter" :
styleConverter = com.sun.javafx.scene.layout.region.BorderStrokeStyleSequenceConverter.getInstance();
break;
case "com.sun.javafx.scene.layout.region.BorderStyleConverter" :
case "com.sun.javafx.scene.layout.region.StrokeBorder$BorderStyleConverter" :
styleConverter = com.sun.javafx.scene.layout.region.BorderStyleConverter.getInstance();
break;
case "com.sun.javafx.scene.layout.region.LayeredBackgroundPositionConverter" :
case "com.sun.javafx.scene.layout.region.BackgroundImage$LayeredBackgroundPositionConverter" :
styleConverter = com.sun.javafx.scene.layout.region.LayeredBackgroundPositionConverter.getInstance();
break;
case "com.sun.javafx.scene.layout.region.LayeredBackgroundSizeConverter" :
case "com.sun.javafx.scene.layout.region.BackgroundImage$LayeredBackgroundSizeConverter" :
styleConverter = com.sun.javafx.scene.layout.region.LayeredBackgroundSizeConverter.getInstance();
break;
case "com.sun.javafx.scene.layout.region.LayeredBorderPaintConverter" :
case "com.sun.javafx.scene.layout.region.StrokeBorder$LayeredBorderPaintConverter" :
styleConverter = com.sun.javafx.scene.layout.region.LayeredBorderPaintConverter.getInstance();
break;
case "com.sun.javafx.scene.layout.region.LayeredBorderStyleConverter" :
case "com.sun.javafx.scene.layout.region.StrokeBorder$LayeredBorderStyleConverter" :
styleConverter = com.sun.javafx.scene.layout.region.LayeredBorderStyleConverter.getInstance();
break;
case "com.sun.javafx.scene.layout.region.RepeatStructConverter" :
case "com.sun.javafx.scene.layout.region.BackgroundImage$BackgroundRepeatConverter" :
case "com.sun.javafx.scene.layout.region.BorderImage$RepeatConverter" :
styleConverter = com.sun.javafx.scene.layout.region.RepeatStructConverter.getInstance();
break;
case "com.sun.javafx.scene.layout.region.SliceSequenceConverter" :
case "com.sun.javafx.scene.layout.region.BorderImage$SliceSequenceConverter" :
styleConverter = com.sun.javafx.scene.layout.region.SliceSequenceConverter.getInstance();
break;
case "com.sun.javafx.scene.layout.region.StrokeBorderPaintConverter" :
case "com.sun.javafx.scene.layout.region.StrokeBorder$BorderPaintConverter" :
styleConverter = com.sun.javafx.scene.layout.region.StrokeBorderPaintConverter.getInstance();
break;
case "com.sun.javafx.scene.layout.region.Margins$Converter" :
styleConverter = com.sun.javafx.scene.layout.region.Margins.Converter.getInstance();
break;
case "com.sun.javafx.scene.layout.region.Margins$SequenceConverter" :
styleConverter = com.sun.javafx.scene.layout.region.Margins.SequenceConverter.getInstance();
break;
case "javafx.scene.layout.CornerRadiiConverter" : // Fix for RT-39665
case "com.sun.javafx.scene.layout.region.CornerRadiiConverter" :
styleConverter = CornerRadiiConverter.getInstance();
break;
// parser stuff
case "javafx.css.converter.DeriveColorConverter":
case "com.sun.javafx.css.parser.DeriveColorConverter" :
styleConverter = DeriveColorConverter.getInstance();
break;
case "javafx.css.converter.DeriveSizeConverter":
case "com.sun.javafx.css.parser.DeriveSizeConverter" :
styleConverter = DeriveSizeConverter.getInstance();
break;
case "javafx.css.converter.LadderConverter":
case "com.sun.javafx.css.parser.LadderConverter" :
styleConverter = LadderConverter.getInstance();
break;
case "javafx.css.converter.StopConverter":
case "com.sun.javafx.css.parser.StopConverter" :
styleConverter = StopConverter.getInstance();
break;
default :
final PlatformLogger logger = Logging.getCSSLogger();
if (logger.isLoggable(Level.SEVERE)) {
logger.severe("StyleConverter : converter Class is null for : "+converterClass);
}
break;
}
return styleConverter;
}
The StringStore class
Since: 9
/**
* The StringStore class
* @since 9
*/
public static class StringStore {
private final Map<String,Integer> stringMap = new HashMap<String,Integer>();
public final List<String> strings = new ArrayList<String>();
public int addString(String s) {
Integer index = stringMap.get(s);
if (index == null) {
index = strings.size();
strings.add(s);
stringMap.put(s,index);
}
return index;
}
public void writeBinary(DataOutputStream os) throws IOException {
os.writeShort(strings.size());
if (stringMap.containsKey(null)) {
Integer index = stringMap.get(null);
os.writeShort(index);
} else {
os.writeShort(-1);
}
for (int n=0; n<strings.size(); n++) {
String s = strings.get(n);
if (s == null) continue;
os.writeUTF(s);
}
}
// TODO: this isn't parallel with writeBinary
public static String[] readBinary(DataInputStream is) throws IOException {
int nStrings = is.readShort();
int nullIndex = is.readShort();
String[] strings = new String[nStrings];
java.util.Arrays.fill(strings, null);
for (int n=0; n<nStrings; n++) {
if (n == nullIndex) continue;
strings[n] = is.readUTF();
}
return strings;
}
}
}