Files
timi-fx/src/main/java/com/imyeyu/fx/config/BindingsConfig.java
2026-01-13 17:50:44 +08:00

331 lines
9.9 KiB
Java

package com.imyeyu.fx.config;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.FloatProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.LongProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleFloatProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleLongProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.ObservableSet;
import javafx.scene.layout.Background;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import com.imyeyu.config.BaseConverter;
import com.imyeyu.config.ConfigLoader;
import com.imyeyu.fx.TimiFX;
import com.imyeyu.fx.utils.BgFill;
import com.imyeyu.java.ref.Ref;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 配置绑定
*
* @author 夜雨
* @since 2021-10-26 10:27
*/
public final class BindingsConfig {
/**
*
*
* @author 夜雨
* @version 2024-04-14 09:30
*/
public abstract static class PropertyConverter<T extends Property<?>, K> extends BaseConverter<T, Object> {
@SuppressWarnings("unchecked")
@Override
protected K serialize(Field field, T t) {
if (t.getValue() == null) {
return null;
}
return (K) t.getValue();
}
}
/**
*
*
* @author 夜雨
* @version 2024-04-28 15:23
*/
public interface ObjectPropertyConverter<T> {
T serialize(Object t);
Object deserialize(String data);
}
public static final PropertyConverter<StringProperty, String> STRING = new PropertyConverter<>() {
@Override
protected StringProperty deserialize(Field field, Object data) {
SimpleStringProperty property = new SimpleStringProperty();
if (data != null) {
property.set(data.toString());
}
return property;
}
};
public static final PropertyConverter<IntegerProperty, Integer> INTEGER = new PropertyConverter<>() {
@Override
protected IntegerProperty deserialize(Field field, Object data) {
SimpleIntegerProperty property = new SimpleIntegerProperty();
if (data != null) {
property.set(Integer.parseInt(data.toString()));
}
return property;
}
};
public static final PropertyConverter<LongProperty, Long> LONG = new PropertyConverter<>() {
@Override
protected LongProperty deserialize(Field field, Object data) {
SimpleLongProperty property = new SimpleLongProperty();
if (data != null) {
property.set(Long.parseLong(data.toString()));
}
return property;
}
};
public static final PropertyConverter<DoubleProperty, Double> DOUBLE = new PropertyConverter<>() {
@Override
protected DoubleProperty deserialize(Field field, Object data) {
SimpleDoubleProperty property = new SimpleDoubleProperty();
if (data != null) {
property.set(Double.parseDouble(data.toString()));
}
return property;
}
};
public static final PropertyConverter<FloatProperty, Float> FLOAT = new PropertyConverter<>() {
@Override
protected FloatProperty deserialize(Field field, Object data) {
SimpleFloatProperty property = new SimpleFloatProperty();
if (data != null) {
property.set(Float.parseFloat(data.toString()));
}
return property;
}
};
public static final PropertyConverter<BooleanProperty, Boolean> BOOLEAN = new PropertyConverter<>() {
@Override
protected BooleanProperty deserialize(Field field, Object data) {
SimpleBooleanProperty property = new SimpleBooleanProperty();
if (data != null) {
property.set(Boolean.parseBoolean(data.toString()));
}
return property;
}
};
/** 颜色转换,配置值格式为 0x11223344 */
public static final BaseConverter<ObjectProperty<Color>, String> COLOR = new BaseConverter<>() {
@Override
protected String serialize(Field field, ObjectProperty<Color> property) {
if (property.getValue() == null) {
return null;
}
return TimiFX.toHexString(property.getValue());
}
@Override
protected ObjectProperty<Color> deserialize(Field field, String data) {
SimpleObjectProperty<Color> property = new SimpleObjectProperty<>();
if (data != null) {
property.set(TimiFX.fromHexString(data));
}
return property;
}
};
/** 颜色配置转换 */
public static final BaseConverter<ObjectProperty<Paint>, String> PAINT = new BaseConverter<>() {
@Override
protected String serialize(Field field, ObjectProperty<Paint> property) {
Paint paint = property.getValue();
if (paint == null) {
return null;
}
if (paint instanceof Color color) {
return TimiFX.toHexString(color);
}
return paint.toString();
}
@Override
protected ObjectProperty<Paint> deserialize(Field field, String data) {
SimpleObjectProperty<Paint> property = new SimpleObjectProperty<>();
if (data != null) {
property.set(Paint.valueOf(data));
}
return property;
}
};
/** 基本填充背景颜色配置转换 */
public static final BaseConverter<ObjectProperty<Background>, String> BG_FILL = new BaseConverter<>() {
@Override
protected String serialize(Field field, ObjectProperty<Background> property) {
if (property.getValue() == null || property.getValue().getFills().isEmpty()) {
return null;
}
return TimiFX.toHexString(Color.valueOf(property.getValue().getFills().getFirst().getFill().toString()));
}
@Override
protected ObjectProperty<Background> deserialize(Field field, String data) {
SimpleObjectProperty<Background> property = new SimpleObjectProperty<>();
if (data != null) {
property.set(new BgFill(data).build());
}
return property;
}
};
public static final BaseConverter<ObjectProperty<?>, String> OBJECT = new BaseConverter<>() {
@Override
protected String serialize(Field field, ObjectProperty<?> property) {
Type genericType = field.getGenericType();
if (genericType instanceof ParameterizedType pt) {
try {
Class<?> propertyGenericClass = Class.forName(pt.getActualTypeArguments()[0].getTypeName());
if (Enum.class.isAssignableFrom(propertyGenericClass)) {
if (property.get() == null) {
return null;
}
return property.get().toString();
}
if (OBJECT_CONVERTER_MAP.containsKey(propertyGenericClass)) {
return OBJECT_CONVERTER_MAP.get(propertyGenericClass).serialize(property.get()).toString();
}
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
throw new RuntimeException("未找到 " + field.getType() + " 属性转换器");
}
@SuppressWarnings("unchecked")
@Override
protected ObjectProperty<?> deserialize(Field field, String data) {
Type genericType = field.getGenericType();
if (genericType instanceof ParameterizedType pt) {
try {
Class<?> propertyGenericClass = Class.forName(pt.getActualTypeArguments()[0].getTypeName());
if (Enum.class.isAssignableFrom(propertyGenericClass)) {
SimpleObjectProperty<Object> property = new SimpleObjectProperty<>();
property.set(Ref.toType((Class<Enum<?>>) propertyGenericClass, data));
return property;
}
if (OBJECT_CONVERTER_MAP.containsKey(propertyGenericClass)) {
SimpleObjectProperty<Object> property = new SimpleObjectProperty<>();
property.set(OBJECT_CONVERTER_MAP.get(propertyGenericClass).deserialize(data));
return property;
}
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
throw new RuntimeException("未找到 " + genericType + " 属性转换器");
}
};
public static final BaseConverter<ObservableList<?>, List<?>> OBS_LIST = new BaseConverter<>() {
@Override
protected List<?> serialize(Field field, ObservableList<?> obsList) {
return new ArrayList<>(obsList);
}
@Override
protected ObservableList<?> deserialize(Field field, List<?> list) {
if (list == null) {
list = new ArrayList<>();
}
return FXCollections.observableList(list);
}
};
public static final BaseConverter<ObservableSet<?>, Set<?>> OBS_SET = new BaseConverter<>() {
@Override
protected Set<?> serialize(Field field, ObservableSet<?> obsSet) {
return new HashSet<>(obsSet);
}
@Override
protected ObservableSet<?> deserialize(Field field, Set<?> set) {
if (set == null) {
set = new HashSet<>();
}
return FXCollections.observableSet(set);
}
};
public static final Map<Class<?>, PropertyConverter<?, ?>> DEFAULT_CONVERTER_MAP = Collections.unmodifiableMap(new HashMap<>() {{
put(StringProperty.class, STRING);
put(IntegerProperty.class, INTEGER);
put(LongProperty.class, LONG);
put(DoubleProperty.class, DOUBLE);
put(FloatProperty.class, FLOAT);
put(BooleanProperty.class, BOOLEAN);
}});
public static final Map<Class<?>, ObjectPropertyConverter<?>> OBJECT_CONVERTER_MAP = new HashMap<>();
public static <T> ConfigLoader<T> build(String path, Class<T> clazz) {
return build(path, path, clazz);
}
public static <T> ConfigLoader<T> build(String srcPath, String distPath, Class<T> clazz) {
ConfigLoader<T> loader = new ConfigLoader<>(srcPath, distPath, clazz);
addAllFXConverter(loader);
return loader;
}
public static void addAllFXConverter(ConfigLoader<?> loader) {
for (Map.Entry<Class<?>, BindingsConfig.PropertyConverter<?, ?>> item : BindingsConfig.DEFAULT_CONVERTER_MAP.entrySet()) {
loader.addConverter(item.getKey(), item.getValue());
}
loader.addConverter(ObjectProperty.class, BindingsConfig.OBJECT);
loader.addConverter(ObservableSet.class, BindingsConfig.OBS_SET);
loader.addConverter(ObservableList.class, BindingsConfig.OBS_LIST);
}
}