diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java
index b5801a41..4781957a 100644
--- a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java
+++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java
@@ -784,14 +784,17 @@ public abstract class FlatLaf
*
* See: https://www.formdev.com/flatlaf/properties-files/
*
- * @param key the key, which is used to determine the value type
+ * @param key the key, which is used to determine the value type if parameter {@code valueType} is {@code null}
* @param value the value string
+ * @param valueType the expected value type, or {@code null}
* @return the binary value
* @throws IllegalArgumentException on syntax errors
* @since TODO
*/
- public static Object parseDefaultsValue( String key, String value ) throws IllegalArgumentException {
- return UIDefaultsLoader.parseValue( key, value );
+ public static Object parseDefaultsValue( String key, String value, Class> valueType )
+ throws IllegalArgumentException
+ {
+ return UIDefaultsLoader.parseValue( key, value, valueType );
}
private static void reSetLookAndFeel() {
diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/IntelliJTheme.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/IntelliJTheme.java
index 5a2fa716..554f7d2b 100644
--- a/flatlaf-core/src/main/java/com/formdev/flatlaf/IntelliJTheme.java
+++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/IntelliJTheme.java
@@ -338,7 +338,7 @@ public class IntelliJTheme
// parse value
try {
- uiValue = UIDefaultsLoader.parseValue( key, valueStr );
+ uiValue = UIDefaultsLoader.parseValue( key, valueStr, null );
} catch( RuntimeException ex ) {
UIDefaultsLoader.logParseError( key, valueStr, ex, false );
return; // ignore invalid value
diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/UIDefaultsLoader.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/UIDefaultsLoader.java
index f71cf72c..9a1e9702 100644
--- a/flatlaf-core/src/main/java/com/formdev/flatlaf/UIDefaultsLoader.java
+++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/UIDefaultsLoader.java
@@ -33,8 +33,10 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.function.Function;
+import javax.swing.Icon;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
+import javax.swing.border.Border;
import javax.swing.UIDefaults.ActiveValue;
import javax.swing.UIDefaults.LazyValue;
import javax.swing.plaf.ColorUIResource;
@@ -241,7 +243,7 @@ class UIDefaultsLoader
String value = resolveValue( (String) e.getValue(), propertiesGetter );
try {
- defaults.put( key, parseValue( key, value, null, resolver, addonClassLoaders ) );
+ defaults.put( key, parseValue( key, value, null, null, resolver, addonClassLoaders ) );
} catch( RuntimeException ex ) {
logParseError( key, value, ex, true );
}
@@ -292,12 +294,13 @@ class UIDefaultsLoader
SCALEDINTEGER, SCALEDFLOAT, SCALEDINSETS, SCALEDDIMENSION, INSTANCE, CLASS, GRAYFILTER, NULL, LAZY }
private static ValueType[] tempResultValueType = new ValueType[1];
+ private static Map, ValueType> javaValueTypes;
- static Object parseValue( String key, String value ) {
- return parseValue( key, value, null, v -> v, Collections.emptyList() );
+ static Object parseValue( String key, String value, Class> valueType ) {
+ return parseValue( key, value, valueType, null, v -> v, Collections.emptyList() );
}
- static Object parseValue( String key, String value, ValueType[] resultValueType,
+ static Object parseValue( String key, String value, Class> javaValueType, ValueType[] resultValueType,
Function resolver, List addonClassLoaders )
{
if( resultValueType == null )
@@ -305,71 +308,106 @@ class UIDefaultsLoader
value = value.trim();
- // null, false, true
- switch( value ) {
- case "null": resultValueType[0] = ValueType.NULL; return null;
- case "false": resultValueType[0] = ValueType.BOOLEAN; return false;
- case "true": resultValueType[0] = ValueType.BOOLEAN; return true;
- }
-
- // check for function "lazy"
- // Syntax: lazy(uiKey)
- if( value.startsWith( "lazy(" ) && value.endsWith( ")" ) ) {
- resultValueType[0] = ValueType.LAZY;
- String uiKey = value.substring( 5, value.length() - 1 ).trim();
- return (LazyValue) t -> {
- return lazyUIManagerGet( uiKey );
- };
+ // null
+ if( value.equals( "null" ) ) {
+ resultValueType[0] = ValueType.NULL;
+ return null;
}
ValueType valueType = ValueType.UNKNOWN;
- // check whether value type is specified in the value
- if( value.startsWith( "#" ) )
- valueType = ValueType.COLOR;
- else if( value.startsWith( "\"" ) && value.endsWith( "\"" ) ) {
- valueType = ValueType.STRING;
- value = value.substring( 1, value.length() - 1 );
- } else if( value.startsWith( TYPE_PREFIX ) ) {
- int end = value.indexOf( TYPE_PREFIX_END );
- if( end != -1 ) {
- try {
- String typeStr = value.substring( TYPE_PREFIX.length(), end );
- valueType = ValueType.valueOf( typeStr.toUpperCase( Locale.ENGLISH ) );
+ if( javaValueType != null ) {
+ if( javaValueTypes == null ) {
+ // create lazy
+ javaValueTypes = new HashMap<>();
+ javaValueTypes.put( String.class, ValueType.STRING );
+ javaValueTypes.put( boolean.class, ValueType.BOOLEAN );
+ javaValueTypes.put( Boolean.class, ValueType.BOOLEAN );
+ javaValueTypes.put( char.class, ValueType.CHARACTER );
+ javaValueTypes.put( Character.class, ValueType.CHARACTER );
+ javaValueTypes.put( int.class, ValueType.INTEGER );
+ javaValueTypes.put( Integer.class, ValueType.INTEGER );
+ javaValueTypes.put( float.class, ValueType.FLOAT );
+ javaValueTypes.put( Float.class, ValueType.FLOAT );
+ javaValueTypes.put( Border.class, ValueType.BORDER );
+ javaValueTypes.put( Icon.class, ValueType.ICON );
+ javaValueTypes.put( Insets.class, ValueType.INSETS );
+ javaValueTypes.put( Dimension.class, ValueType.DIMENSION );
+ javaValueTypes.put( Color.class, ValueType.COLOR );
+ }
- // remove type from value
- value = value.substring( end + TYPE_PREFIX_END.length() );
- } catch( IllegalArgumentException ex ) {
- // ignore
+ // map java value type to parser value type
+ valueType = javaValueTypes.get( javaValueType );
+ if( valueType == null )
+ throw new IllegalArgumentException( "unsupported value type '" + javaValueType.getName() + "'" );
+
+ // remove '"' from strings
+ if( valueType == ValueType.STRING && value.startsWith( "\"" ) && value.endsWith( "\"" ) )
+ value = value.substring( 1, value.length() - 1 );
+ } else {
+ // false, true
+ switch( value ) {
+ case "false": resultValueType[0] = ValueType.BOOLEAN; return false;
+ case "true": resultValueType[0] = ValueType.BOOLEAN; return true;
+ }
+
+ // check for function "lazy"
+ // Syntax: lazy(uiKey)
+ if( value.startsWith( "lazy(" ) && value.endsWith( ")" ) ) {
+ resultValueType[0] = ValueType.LAZY;
+ String uiKey = value.substring( 5, value.length() - 1 ).trim();
+ return (LazyValue) t -> {
+ return lazyUIManagerGet( uiKey );
+ };
+ }
+
+ // check whether value type is specified in the value
+ if( value.startsWith( "#" ) )
+ valueType = ValueType.COLOR;
+ else if( value.startsWith( "\"" ) && value.endsWith( "\"" ) ) {
+ valueType = ValueType.STRING;
+ value = value.substring( 1, value.length() - 1 );
+ } else if( value.startsWith( TYPE_PREFIX ) ) {
+ int end = value.indexOf( TYPE_PREFIX_END );
+ if( end != -1 ) {
+ try {
+ String typeStr = value.substring( TYPE_PREFIX.length(), end );
+ valueType = ValueType.valueOf( typeStr.toUpperCase( Locale.ENGLISH ) );
+
+ // remove type from value
+ value = value.substring( end + TYPE_PREFIX_END.length() );
+ } catch( IllegalArgumentException ex ) {
+ // ignore
+ }
}
}
- }
- // determine value type from key
- if( valueType == ValueType.UNKNOWN ) {
- if( key.endsWith( "UI" ) )
- valueType = ValueType.STRING;
- else if( key.endsWith( "Color" ) ||
- (key.endsWith( "ground" ) &&
- (key.endsWith( ".background" ) || key.endsWith( "Background" ) || key.equals( "background" ) ||
- key.endsWith( ".foreground" ) || key.endsWith( "Foreground" ) || key.equals( "foreground" ))) )
- valueType = ValueType.COLOR;
- else if( key.endsWith( ".border" ) || key.endsWith( "Border" ) )
- valueType = ValueType.BORDER;
- else if( key.endsWith( ".icon" ) || key.endsWith( "Icon" ) )
- valueType = ValueType.ICON;
- else if( key.endsWith( ".margin" ) || key.equals( "margin" ) ||
- key.endsWith( ".padding" ) || key.equals( "padding" ) ||
- key.endsWith( "Margins" ) || key.endsWith( "Insets" ) )
- valueType = ValueType.INSETS;
- else if( key.endsWith( "Size" ) )
- valueType = ValueType.DIMENSION;
- else if( key.endsWith( "Width" ) || key.endsWith( "Height" ) )
- valueType = ValueType.INTEGER;
- else if( key.endsWith( "Char" ) )
- valueType = ValueType.CHARACTER;
- else if( key.endsWith( "grayFilter" ) )
- valueType = ValueType.GRAYFILTER;
+ // determine value type from key
+ if( valueType == ValueType.UNKNOWN ) {
+ if( key.endsWith( "UI" ) )
+ valueType = ValueType.STRING;
+ else if( key.endsWith( "Color" ) ||
+ (key.endsWith( "ground" ) &&
+ (key.endsWith( ".background" ) || key.endsWith( "Background" ) || key.equals( "background" ) ||
+ key.endsWith( ".foreground" ) || key.endsWith( "Foreground" ) || key.equals( "foreground" ))) )
+ valueType = ValueType.COLOR;
+ else if( key.endsWith( ".border" ) || key.endsWith( "Border" ) )
+ valueType = ValueType.BORDER;
+ else if( key.endsWith( ".icon" ) || key.endsWith( "Icon" ) )
+ valueType = ValueType.ICON;
+ else if( key.endsWith( ".margin" ) || key.equals( "margin" ) ||
+ key.endsWith( ".padding" ) || key.equals( "padding" ) ||
+ key.endsWith( "Margins" ) || key.endsWith( "Insets" ) )
+ valueType = ValueType.INSETS;
+ else if( key.endsWith( "Size" ) )
+ valueType = ValueType.DIMENSION;
+ else if( key.endsWith( "Width" ) || key.endsWith( "Height" ) )
+ valueType = ValueType.INTEGER;
+ else if( key.endsWith( "Char" ) )
+ valueType = ValueType.CHARACTER;
+ else if( key.endsWith( "grayFilter" ) )
+ valueType = ValueType.GRAYFILTER;
+ }
}
resultValueType[0] = valueType;
@@ -377,6 +415,7 @@ class UIDefaultsLoader
// parse value
switch( valueType ) {
case STRING: return value;
+ case BOOLEAN: return parseBoolean( value );
case CHARACTER: return parseCharacter( value );
case INTEGER: return parseInteger( value, true );
case FLOAT: return parseFloat( value, true );
@@ -869,6 +908,14 @@ class UIDefaultsLoader
return val;
}
+ private static Boolean parseBoolean( String value ) {
+ switch( value ) {
+ case "false": return false;
+ case "true": return true;
+ }
+ throw new IllegalArgumentException( "invalid boolean '" + value + "'" );
+ }
+
private static Character parseCharacter( String value ) {
if( value.length() != 1 )
throw new IllegalArgumentException( "invalid character '" + value + "'" );
diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatStyleSupport.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatStyleSupport.java
index 882dd7e6..d1387ca7 100644
--- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatStyleSupport.java
+++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatStyleSupport.java
@@ -198,7 +198,7 @@ public class FlatStyleSupport
if( key.startsWith( "[" ) )
key = key.substring( key.indexOf( ']' ) + 1 );
- return FlatLaf.parseDefaultsValue( key, value );
+ return FlatLaf.parseDefaultsValue( key, value, null );
}
/**
diff --git a/flatlaf-core/src/test/java/com/formdev/flatlaf/TestUIDefaultsLoader.java b/flatlaf-core/src/test/java/com/formdev/flatlaf/TestUIDefaultsLoader.java
new file mode 100644
index 00000000..b940debe
--- /dev/null
+++ b/flatlaf-core/src/test/java/com/formdev/flatlaf/TestUIDefaultsLoader.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2021 FormDev Software GmbH
+ *
+ * Licensed 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
+ *
+ * https://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 com.formdev.flatlaf;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Insets;
+import org.junit.jupiter.api.Test;
+
+/**
+ * @author Karl Tauber
+ */
+public class TestUIDefaultsLoader
+{
+ @Test
+ void parseValue() {
+ assertEquals( null, UIDefaultsLoader.parseValue( "dummy", "null", null ) );
+ assertEquals( false, UIDefaultsLoader.parseValue( "dummy", "false", null ) );
+ assertEquals( true, UIDefaultsLoader.parseValue( "dummy", "true", null ) );
+
+ assertEquals( "hello", UIDefaultsLoader.parseValue( "dummy", "hello", null ) );
+ assertEquals( "hello", UIDefaultsLoader.parseValue( "dummy", "\"hello\"", null ) );
+ assertEquals( "null", UIDefaultsLoader.parseValue( "dummy", "\"null\"", null ) );
+
+ assertEquals( 'a', UIDefaultsLoader.parseValue( "dummyChar", "a", null ) );
+ assertEquals( 123, UIDefaultsLoader.parseValue( "dummy", "123", null ) );
+ assertEquals( 123, UIDefaultsLoader.parseValue( "dummyWidth", "123", null ) );
+ assertEquals( 1.23f, UIDefaultsLoader.parseValue( "dummy", "1.23", null ) );
+ assertEquals( 1.23f, UIDefaultsLoader.parseValue( "dummyWidth", "{float}1.23", null ) );
+
+ assertEquals( new Insets( 2,2,2,2 ), UIDefaultsLoader.parseValue( "dummyInsets", "2,2,2,2", null ) );
+ assertEquals( new Dimension( 2,2 ), UIDefaultsLoader.parseValue( "dummySize", "2,2", null ) );
+ assertEquals( new Color( 0xff0000 ), UIDefaultsLoader.parseValue( "dummy", "#f00", null ) );
+ assertEquals( new Color( 0xff0000 ), UIDefaultsLoader.parseValue( "dummyColor", "#f00", null ) );
+ }
+
+ @Test
+ void parseValueWithJavaType() {
+ assertEquals( null, UIDefaultsLoader.parseValue( "dummy", "null", String.class ) );
+ assertEquals( false, UIDefaultsLoader.parseValue( "dummy", "false", boolean.class ) );
+ assertEquals( true, UIDefaultsLoader.parseValue( "dummy", "true", Boolean.class ) );
+
+ assertEquals( "hello", UIDefaultsLoader.parseValue( "dummy", "hello", String.class ) );
+ assertEquals( "hello", UIDefaultsLoader.parseValue( "dummy", "\"hello\"", String.class ) );
+ assertEquals( "null", UIDefaultsLoader.parseValue( "dummy", "\"null\"", String.class ) );
+ assertEquals( null, UIDefaultsLoader.parseValue( "dummy", "null", String.class ) );
+
+ assertEquals( 'a', UIDefaultsLoader.parseValue( "dummy", "a", char.class ) );
+ assertEquals( 'a', UIDefaultsLoader.parseValue( "dummy", "a", Character.class ) );
+ assertEquals( 123, UIDefaultsLoader.parseValue( "dummy", "123", int.class ) );
+ assertEquals( 123, UIDefaultsLoader.parseValue( "dummy", "123", Integer.class ) );
+ assertEquals( 1.23f, UIDefaultsLoader.parseValue( "dummy", "1.23", float.class ) );
+ assertEquals( 1.23f, UIDefaultsLoader.parseValue( "dummy", "1.23", Float.class ) );
+
+ assertEquals( new Insets( 2,2,2,2 ), UIDefaultsLoader.parseValue( "dummy", "2,2,2,2", Insets.class ) );
+ assertEquals( new Dimension( 2,2 ), UIDefaultsLoader.parseValue( "dummy", "2,2", Dimension.class ) );
+ assertEquals( new Color( 0xff0000 ), UIDefaultsLoader.parseValue( "dummy", "#f00", Color.class ) );
+ }
+}
diff --git a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/UIDefaultsLoaderAccessor.java b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/UIDefaultsLoaderAccessor.java
index fb4698d1..d6b35f90 100644
--- a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/UIDefaultsLoaderAccessor.java
+++ b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/UIDefaultsLoaderAccessor.java
@@ -56,7 +56,8 @@ public class UIDefaultsLoaderAccessor
Function resolver )
{
ValueType[] resultValueType2 = new ValueType[1];
- Object result = UIDefaultsLoader.parseValue( key, value, resultValueType2, resolver, Collections.emptyList() );
+ Object result = UIDefaultsLoader.parseValue( key, value, null,
+ resultValueType2, resolver, Collections.emptyList() );
resultValueType[0] = resultValueType2[0];
return result;
}