46 import javafx.scene.paint.Paint; 47 import javafx.scene.text.Font; 48 import javafx.util.Duration; 49 50 import com.sun.javafx.scene.layout.region.CornerRadiiConverter; 51 import com.sun.javafx.util.Logging; 52 import sun.util.logging.PlatformLogger; 53 import sun.util.logging.PlatformLogger.Level; 54 55 import java.io.DataInputStream; 56 import java.io.DataOutputStream; 57 import java.io.IOException; 58 import java.util.ArrayList; 59 import java.util.HashMap; 60 import java.util.List; 61 import java.util.Map; 62 import java.util.WeakHashMap; 63 64 65 /** 66 * StyleConverter converts {@code ParsedValue&tl;F,T>} from type F to type T. The 67 * {@link CssMetaData} API requires a {@code StyleConverter} which is used 68 * when computing a value for the {@see StyleableProperty}. There are 69 * a number of predefined converters which are accessible by the static 70 * methods of this class. 71 * 72 * F is the type of the parsed value, T is the converted type of 73 * the ParsedValueImpl. For example, a converter from String to Color would 74 * be declared 75 * <p> 76 * <code>public Color convert(ParsedValueImpl<String,Color> value, Font font)</code> 77 * </p> 78 * 79 * @see ParsedValue 80 * @see StyleableProperty 81 * @since JavaFX 8.0 82 */ 83 public class StyleConverter<F, T> { 84 85 /** 86 * Convert from the parsed CSS value to the target property type. 87 * 88 * @param value The {@link ParsedValue} to convert 89 * @param font The {@link Font} to use when converting a 90 * <a href="http://www.w3.org/TR/css3-values/#relative-lengths">relative</a> 91 * value. 92 */ 93 @SuppressWarnings("unchecked") 94 public T convert(ParsedValue<F,T> value, Font font) { 95 // unchecked! 96 return (T) value.getValue(); 97 } 98 99 /** 100 * @return A {@code StyleConverter} that converts "true" or "false" to {@code Boolean} 101 * @see Boolean#valueOf(java.lang.String) 102 */ 103 public static StyleConverter<String,Boolean> getBooleanConverter() { 104 return BooleanConverter.getInstance(); 105 } 106 107 /** 108 * @return A {@code StyleConverter} that converts a String 109 * representation of a duration to a {@link Duration} 110 * 111 * @since JavaFX 8u40 116 117 /** 118 * @return A {@code StyleConverter} that converts a String 119 * representation of a web color to a {@code Color} 120 * @see Color#web(java.lang.String) 121 */ 122 public static StyleConverter<String,Color> getColorConverter() { 123 return ColorConverter.getInstance(); 124 } 125 126 /** 127 * @return A {@code StyleConverter} that converts a parsed representation 128 * of an {@code Effect} to an {@code Effect} 129 * @see Effect 130 */ 131 public static StyleConverter<ParsedValue[], Effect> getEffectConverter() { 132 return EffectConverter.getInstance(); 133 } 134 135 /** 136 * @return A {@code StyleConverter} that converts a String representation 137 * of an {@code Enum} to an {@code Enum} 138 * @see Enum#valueOf(java.lang.Class, java.lang.String) 139 */ 140 public static <E extends Enum<E>> StyleConverter<String, ? extends Enum<?>> getEnumConverter(Class<E> enumClass) { 141 // TODO: reuse EnumConverter instances 142 EnumConverter<E> converter; 143 converter = new EnumConverter<>(enumClass); 144 return converter; 145 } 146 147 /** 148 * @return A {@code StyleConverter} that converts a parsed representation 149 * of a {@code Font} to an {@code Font}. 150 * @see Font#font(java.lang.String, javafx.scene.text.FontWeight, javafx.scene.text.FontPosture, double) 151 */ 152 public static StyleConverter<ParsedValue[], Font> getFontConverter() { 153 return FontConverter.getInstance(); 154 } 155 156 /** 157 * @return A {@code StyleConverter} that converts a [<length> | 158 * <percentage>]{1,4} to an {@code Insets}. 159 */ 160 public static StyleConverter<ParsedValue[], Insets> getInsetsConverter() { 161 return InsetsConverter.getInstance(); 162 } 163 164 /** 165 * @return A {@code StyleConverter} that converts a parsed representation 166 * of a {@code Paint} to a {@code Paint}. 167 */ 168 public static StyleConverter<ParsedValue<?, Paint>, Paint> getPaintConverter() { 169 return PaintConverter.getInstance(); 170 } 171 172 /** 173 * CSS length and number values are parsed into a Size object that is 174 * converted to a Number before the value is applied. If the property is 175 * a {@code Number} type other than Double, the 176 * {@link CssMetaData#set(javafx.scene.Node, java.lang.Object, javafx.css.Origin) set} 177 * method of ({@code CssMetaData} can be over-ridden to convert the Number 178 * to the correct type. For example, if the property is an {@code IntegerProperty}: 179 * <code><pre> 180 * {@literal @}Override public void set(MyNode node, Number value, Origin origin) { 181 * if (value != null) { 182 * super.set(node, value.intValue(), origin); 183 * } else { 184 * super.set(node, value, origin); 185 * } 186 * } 187 * </pre></code> 188 * @return A {@code StyleConverter} that converts a parsed representation 189 * of a CSS length or number value to a {@code Number} that is an instance 190 * of {@code Double}. 191 */ 192 public static StyleConverter<?, Number> getSizeConverter() { 193 return SizeConverter.getInstance(); 194 } 195 196 /** 197 * A converter for quoted strings which may have embedded unicode characters. 198 * @return A {@code StyleConverter} that converts a representation of a 199 * CSS string value to a {@code String}. 200 */ 201 public static StyleConverter<String,String> getStringConverter() { 202 return StringConverter.getInstance(); 203 } 204 205 /** 206 * A converter for URL strings. 207 * @return A {@code StyleConverter} that converts a representation of a 208 * CSS URL value to a {@code String}. 209 */ 210 public static StyleConverter<ParsedValue[], String> getUrlConverter() { 211 return URLConverter.getInstance(); 212 } 213 214 215 216 217 /** 218 * Convert from the constituent values to the target property type. 219 * Implemented by Types that have Keys with subKeys. 220 * 221 * @since 9 222 */ 223 public T convert(Map<CssMetaData<? extends Styleable, ?>,Object> convertedValues) { 224 return null; 225 } 226 227 /** 228 * 229 * @since 9 230 */ 231 public void writeBinary(DataOutputStream os, StringStore sstore) 232 throws IOException { 233 234 String cname = getClass().getName(); 235 int index = sstore.addString(cname); 236 os.writeShort(index); 237 } 238 239 private static Map<ParsedValue, Object> cache; 240 241 /** 242 * 243 * @since 9 244 */ 245 public static void clearCache() { 246 if (cache != null) { 247 cache.clear(); 248 } 249 } 250 251 /** 252 * 253 * @since 9 254 */ 255 protected T getCachedValue(ParsedValue key) { 256 if (cache != null) { 257 return (T)cache.get(key); 258 } 259 return null; 260 } 261 262 /** 263 * 264 * @since 9 265 */ 266 protected void cacheValue(ParsedValue key, Object value) { 267 if (cache == null) cache = new WeakHashMap<>(); 268 cache.put(key, value); 269 } 270 271 // map of StyleConverter class name to StyleConverter 272 private static Map<String,StyleConverter<?, ?>> tmap; 273 274 /** 275 * 276 * @since 9 277 */ 278 @SuppressWarnings("rawtypes") 279 public static StyleConverter<?,?> readBinary(DataInputStream is, String[] strings) 280 throws IOException { 281 282 int index = is.readShort(); 283 String cname = strings[index]; 284 285 if (cname == null || cname.isEmpty()) return null; 286 287 if (cname.startsWith("com.sun.javafx.css.converters.")) { 288 // JavaFX 9: converter classes were moved from 289 // com.sun.javafx.css.converters.* to javafx.css.converter.* 290 // Note: the word 'converters' has become 'converter'. 291 cname = "javafx.css.converter." + cname.substring("com.sun.javafx.css.converters.".length()); 292 } 293 if (cname.startsWith("javafx.css.converter.EnumConverter")) { 294 return (StyleConverter)javafx.css.converter.EnumConverter.readBinary(is, strings); 295 } | 46 import javafx.scene.paint.Paint; 47 import javafx.scene.text.Font; 48 import javafx.util.Duration; 49 50 import com.sun.javafx.scene.layout.region.CornerRadiiConverter; 51 import com.sun.javafx.util.Logging; 52 import sun.util.logging.PlatformLogger; 53 import sun.util.logging.PlatformLogger.Level; 54 55 import java.io.DataInputStream; 56 import java.io.DataOutputStream; 57 import java.io.IOException; 58 import java.util.ArrayList; 59 import java.util.HashMap; 60 import java.util.List; 61 import java.util.Map; 62 import java.util.WeakHashMap; 63 64 65 /** 66 * StyleConverter converts {@code ParsedValue<F,T>} 67 * from type {@code F} to type {@code T}. The 68 * {@link CssMetaData} API requires a {@code StyleConverter} which is used 69 * when computing a value for the {@code StyleableProperty}. There are 70 * a number of predefined converters which are accessible by the static 71 * methods of this class. 72 * 73 * {@code F} is the type of the parsed value and {@code T} is the converted type of 74 * the ParsedValueImpl. For example, a converter from String to Color would 75 * be declared 76 * <p> 77 * <code>public Color convert(ParsedValueImpl<String,Color> value, Font font)</code> 78 * </p> 79 * 80 * @param <F> the type of the parsed value 81 * @param <T> the converted type of the ParsedValueImpl 82 * 83 * @see ParsedValue 84 * @see StyleableProperty 85 * @since JavaFX 8.0 86 */ 87 public class StyleConverter<F, T> { 88 89 /** 90 * Convert from the parsed CSS value to the target property type. 91 * 92 * @param value The {@link ParsedValue} to convert 93 * @param font The {@link Font} to use when converting a 94 * <a href="http://www.w3.org/TR/css3-values/#relative-lengths">relative</a> 95 * value. 96 * @return the converted target property type. 97 */ 98 @SuppressWarnings("unchecked") 99 public T convert(ParsedValue<F,T> value, Font font) { 100 // unchecked! 101 return (T) value.getValue(); 102 } 103 104 /** 105 * @return A {@code StyleConverter} that converts "true" or "false" to {@code Boolean} 106 * @see Boolean#valueOf(java.lang.String) 107 */ 108 public static StyleConverter<String,Boolean> getBooleanConverter() { 109 return BooleanConverter.getInstance(); 110 } 111 112 /** 113 * @return A {@code StyleConverter} that converts a String 114 * representation of a duration to a {@link Duration} 115 * 116 * @since JavaFX 8u40 121 122 /** 123 * @return A {@code StyleConverter} that converts a String 124 * representation of a web color to a {@code Color} 125 * @see Color#web(java.lang.String) 126 */ 127 public static StyleConverter<String,Color> getColorConverter() { 128 return ColorConverter.getInstance(); 129 } 130 131 /** 132 * @return A {@code StyleConverter} that converts a parsed representation 133 * of an {@code Effect} to an {@code Effect} 134 * @see Effect 135 */ 136 public static StyleConverter<ParsedValue[], Effect> getEffectConverter() { 137 return EffectConverter.getInstance(); 138 } 139 140 /** 141 * @param <E> A {@code StyleConverter} that converts a String representation 142 * of an {@code Enum} to an {@code Enum} 143 * @param enumClass the enum Class 144 * @return A {@code StyleConverter} that converts a String representation 145 * of an {@code Enum} to an {@code Enum} 146 * @see Enum#valueOf(java.lang.Class, java.lang.String) 147 */ 148 public static <E extends Enum<E>> StyleConverter<String, ? extends Enum<?>> getEnumConverter(Class<E> enumClass) { 149 // TODO: reuse EnumConverter instances 150 EnumConverter<E> converter; 151 converter = new EnumConverter<>(enumClass); 152 return converter; 153 } 154 155 /** 156 * @return A {@code StyleConverter} that converts a parsed representation 157 * of a {@code Font} to an {@code Font}. 158 * @see Font#font(java.lang.String, javafx.scene.text.FontWeight, javafx.scene.text.FontPosture, double) 159 */ 160 public static StyleConverter<ParsedValue[], Font> getFontConverter() { 161 return FontConverter.getInstance(); 162 } 163 164 /** 165 * @return A {@code StyleConverter} that converts a [<length> | 166 * <percentage>]{1,4} to an {@code Insets}. 167 */ 168 public static StyleConverter<ParsedValue[], Insets> getInsetsConverter() { 169 return InsetsConverter.getInstance(); 170 } 171 172 /** 173 * @return A {@code StyleConverter} that converts a parsed representation 174 * of a {@code Paint} to a {@code Paint}. 175 */ 176 public static StyleConverter<ParsedValue<?, Paint>, Paint> getPaintConverter() { 177 return PaintConverter.getInstance(); 178 } 179 180 /** 181 * CSS length and number values are parsed into a Size object that is 182 * converted to a Number before the value is applied. If the property is 183 * a {@code Number} type other than {@code Double}, the set method 184 * of ({@code CssMetaData} can be overridden to convert the {@code Number} 185 * to the correct type. For example, if the property is an {@code IntegerProperty}: 186 * <code> 187 * {@literal @}Override public void set(MyNode node, Number value, Origin origin) { 188 * if (value != null) { 189 * super.set(node, value.intValue(), origin); 190 * } else { 191 * super.set(node, value, origin); 192 * } 193 * } 194 * </code> 195 * @return A {@code StyleConverter} that converts a parsed representation 196 * of a CSS length or number value to a {@code Number} that is an instance 197 * of {@code Double}. 198 */ 199 public static StyleConverter<?, Number> getSizeConverter() { 200 return SizeConverter.getInstance(); 201 } 202 203 /** 204 * A converter for quoted strings which may have embedded unicode characters. 205 * @return A {@code StyleConverter} that converts a representation of a 206 * CSS string value to a {@code String}. 207 */ 208 public static StyleConverter<String,String> getStringConverter() { 209 return StringConverter.getInstance(); 210 } 211 212 /** 213 * A converter for URL strings. 214 * @return A {@code StyleConverter} that converts a representation of a 215 * CSS URL value to a {@code String}. 216 */ 217 public static StyleConverter<ParsedValue[], String> getUrlConverter() { 218 return URLConverter.getInstance(); 219 } 220 221 222 223 224 /** 225 * Convert from the constituent values to the target property type. 226 * Implemented by Types that have Keys with subKeys. 227 * 228 * @param convertedValues the constituent values 229 * @return the target property type 230 * @since 9 231 */ 232 public T convert(Map<CssMetaData<? extends Styleable, ?>,Object> convertedValues) { 233 return null; 234 } 235 236 /** 237 * 238 * @param os the data output stream 239 * @param sstore the string store 240 * @throws java.io.IOException the exception 241 * @since 9 242 */ 243 public void writeBinary(DataOutputStream os, StringStore sstore) 244 throws IOException { 245 246 String cname = getClass().getName(); 247 int index = sstore.addString(cname); 248 os.writeShort(index); 249 } 250 251 private static Map<ParsedValue, Object> cache; 252 253 /** 254 * 255 * @since 9 256 */ 257 public static void clearCache() { 258 if (cache != null) { 259 cache.clear(); 260 } 261 } 262 263 /** 264 * 265 * @param key the key 266 * @return the cached value 267 * @since 9 268 */ 269 protected T getCachedValue(ParsedValue key) { 270 if (cache != null) { 271 return (T)cache.get(key); 272 } 273 return null; 274 } 275 276 /** 277 * 278 * @param key the key 279 * @param value the value 280 * @since 9 281 */ 282 protected void cacheValue(ParsedValue key, Object value) { 283 if (cache == null) cache = new WeakHashMap<>(); 284 cache.put(key, value); 285 } 286 287 // map of StyleConverter class name to StyleConverter 288 private static Map<String,StyleConverter<?, ?>> tmap; 289 290 /** 291 * 292 * @param is the data input stream 293 * @param strings the strings 294 * @return the style converter 295 * @throws java.io.IOException the exception 296 * @since 9 297 */ 298 @SuppressWarnings("rawtypes") 299 public static StyleConverter<?,?> readBinary(DataInputStream is, String[] strings) 300 throws IOException { 301 302 int index = is.readShort(); 303 String cname = strings[index]; 304 305 if (cname == null || cname.isEmpty()) return null; 306 307 if (cname.startsWith("com.sun.javafx.css.converters.")) { 308 // JavaFX 9: converter classes were moved from 309 // com.sun.javafx.css.converters.* to javafx.css.converter.* 310 // Note: the word 'converters' has become 'converter'. 311 cname = "javafx.css.converter." + cname.substring("com.sun.javafx.css.converters.".length()); 312 } 313 if (cname.startsWith("javafx.css.converter.EnumConverter")) { 314 return (StyleConverter)javafx.css.converter.EnumConverter.readBinary(is, strings); 315 } |