From 783e2af1cd6192ccdfee30f0411c258f8e9187b6 Mon Sep 17 00:00:00 2001 From: lemon Date: Fri, 23 Aug 2024 16:52:17 +0800 Subject: [PATCH 01/10] =?UTF-8?q?REPORT-127437=20feat:=E9=80=82=E9=85=8D?= =?UTF-8?q?=E6=8F=92=E4=BB=B6=E5=9B=BE=E6=A0=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../theme/icon/plugin/PluginIconManager.java | 213 ++++++++++++++++++ .../fine/theme/icon/plugin/PluginIconSet.java | 136 +++++++++++ .../theme/icon/plugin/PluginLazyIcon.java | 129 +++++++++++ .../com/fr/design/fun/LazyIconProvider.java | 68 ++++++ .../fun/impl/AbstractLazyIconProvider.java | 71 ++++++ 5 files changed, 617 insertions(+) create mode 100644 designer-base/src/main/java/com/fine/theme/icon/plugin/PluginIconManager.java create mode 100644 designer-base/src/main/java/com/fine/theme/icon/plugin/PluginIconSet.java create mode 100644 designer-base/src/main/java/com/fine/theme/icon/plugin/PluginLazyIcon.java create mode 100644 designer-base/src/main/java/com/fr/design/fun/LazyIconProvider.java create mode 100644 designer-base/src/main/java/com/fr/design/fun/impl/AbstractLazyIconProvider.java diff --git a/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginIconManager.java b/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginIconManager.java new file mode 100644 index 0000000000..8648396f75 --- /dev/null +++ b/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginIconManager.java @@ -0,0 +1,213 @@ +package com.fine.theme.icon.plugin; + +import com.fine.theme.icon.IconException; +import com.fine.theme.icon.IconManager; +import com.fine.theme.icon.IconSet; +import com.fine.theme.icon.IconType; +import com.fine.theme.icon.LazyIcon; +import com.fr.base.extension.FileExtension; +import com.fr.general.IOUtils; +import com.fr.log.FineLoggerFactory; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.Icon; +import java.awt.Dimension; +import java.lang.ref.WeakReference; +import java.util.HashMap; +import java.util.Map; + +/** + * 管理插件图标集 + * + * @author lemon + * @since + * Created on 2024/08/23 + */ +public class PluginIconManager { + + public static final String ICON_DISABLE_SUFFIX = "_disable"; + public static final Dimension DEFAULT_DIMENSION = new Dimension(16, 16); + private static final Map SOURCE_ICON_MAPS = new HashMap<>(2); + private static final HashMap>> CACHE = new HashMap<>(); + + + /** + * 获取图标集 + * + * @param id 图标集ID + * @return 图标集 + */ + public static IconSet getSet(String source, String id) { + IconSet set = SOURCE_ICON_MAPS.get(source); + + if (set != null && set.getId().equals(id)) { + return set; + } + throw new IconException("[PluginIconManager] Can not find icon set by id: " + id); + } + + /** + * 添加图标集 + * + * @param source 插件 + * @param set 图标集 + */ + public static void addSet(@NotNull String source, @NotNull IconSet set) { + if (SOURCE_ICON_MAPS.containsKey(source)) { + FineLoggerFactory.getLogger().warn("[PluginIconManager] plugin:{} icon set already exists: " + source); + } + SOURCE_ICON_MAPS.put(source, set); + clearCacheBySource(source); + } + + /** + * 更新指定插件图标集 + * + * @param source 插件 + * @param set 图标集 + */ + public static void updateSet(@NotNull String source, @NotNull IconSet set) { + SOURCE_ICON_MAPS.put(source, set); + clearCacheBySource(source); + } + + /** + * 删除指定插件图标集 + * + * @param source 插件 + */ + public static void removeSet(@NotNull String source) { + SOURCE_ICON_MAPS.remove(source); + clearCacheBySource(source); + } + + /** + * 根据图标ID获取图标 + *

+ * 查找路径 + * 1)查找图集图标 + * 2)路径为图片图标,从路径再查找 + * 3)提供默认svg图标 + * + * @param id 图标ID + * @param 图标类型 + * @return 图标 + */ + @NotNull + public static I getIcon(@NotNull String source, @NotNull final String id, @NotNull Dimension dimension, @NotNull IconType type) { + Icon icon = findIcon(source, id, dimension, type); + if (icon == null) { + // 只有找不到再进行其他fallback,提升效率 + if (IconManager.isImageIcon(id)) { + return (I) fallbackLegacyIcon(id); + } else { + FineLoggerFactory.getLogger().warn("[PluginIconManager] Can not find icon by id: " + id); + return (I) new LazyIcon("default"); + } + } + return (I) icon; + } + + private static Icon fallbackLegacyIcon(String id) { + return IOUtils.readIcon(id); + } + + @Nullable + private static I findIcon(String source, String id, Dimension dimension, IconType type) { + String cacheKey = genCacheKey(source, id, dimension, type); + HashMap> sourceCache = CACHE.getOrDefault(cacheKey, new HashMap<>(64)); + final WeakReference reference = sourceCache.get(cacheKey); + I icon = reference != null ? (I) reference.get() : null; + if (icon == null) { + IconSet set = SOURCE_ICON_MAPS.get(source); + if (set == null) { + return icon; + } + Icon f = set.findIcon(id, dimension, type); + if (f != null) { + icon = (I) f; + sourceCache.put(cacheKey, new WeakReference<>(icon)); + CACHE.put(source, sourceCache); + } + } + return icon; + } + + + /** + * 生成缓存key + * + * @param id id + * @param dimension 尺寸 + * @param type 图标类型 + * @return 缓存key + */ + public static @NotNull String genCacheKey(String source, String id, Dimension dimension, IconType type) { + if (DEFAULT_DIMENSION.equals(dimension)) { + return source + "_" + id + "_" + type; + } + return source + "_" + id + "_" + dimension.width + "_" + dimension.height + "_" + type; + } + + /** + * 是否SVG图标格式 + * + * @param path 路径 + * @return 是否SVG图标格式 + */ + public static boolean isSvgIcon(String path) { + return FileExtension.SVG.matchExtension(path); + } + + /** + * 是否支持的图片图标格式,目前只支持png和jpg + * + * @param path 路径 + * @return 是否支持的图片图标格式 + */ + public static boolean isImageIcon(String path) { + return FileExtension.PNG.matchExtension(path) + || FileExtension.JPG.matchExtension(path); + } + + /** + * 判断是否存在指定id的icon,非io读取行为,而是从已注册的sourceMap中遍历判断 + * + * @param id id + * @return 是否存在 + */ + public static boolean existIcon(String id, String source) { + IconSet set = SOURCE_ICON_MAPS.get(source); + if (set != null && set.getIds().contains(id)) { + return true; + } + return false; + } + + /** + * 清理所有缓存 + */ + public static void clearCache() { + CACHE.clear(); + } + + /** + * 清楚指定插件缓存 + * @param source 插件标识 + */ + public static void clearCacheBySource(String source) { + CACHE.remove(source); + } + + /** + * 查找灰化图标 + * + * @param path 原始路径 + * @return 灰化路径 + */ + public static String findDisablePath(String path) { + int i = path.lastIndexOf('.'); + return path.substring(0, i) + ICON_DISABLE_SUFFIX + path.substring(i); + } +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginIconSet.java b/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginIconSet.java new file mode 100644 index 0000000000..151322d725 --- /dev/null +++ b/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginIconSet.java @@ -0,0 +1,136 @@ +package com.fine.theme.icon.plugin; + +import com.fine.theme.icon.AbstractIconSet; +import com.fine.theme.icon.IconManager; +import com.fine.theme.icon.IconType; +import com.formdev.flatlaf.json.Json; +import com.formdev.flatlaf.json.ParseException; +import com.fr.stable.StringUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.StandardCharsets; +import java.util.Map; +import java.util.Objects; + +/** + * 插件图标集 + * + * @author lemon + * @since + * Created on 2024/08/20 + */ +public class PluginIconSet extends AbstractIconSet { + + private String base; + + + public PluginIconSet(PluginUrlIconResource resource, Map iconId2Path) { + addIconWithMap(iconId2Path); + + if (resource.getPath() == null) { + return; + } + Map json; + try (InputStream in = resource.getInputStream()) { + try (Reader reader = new InputStreamReader(in, StandardCharsets.UTF_8)) { + json = (Map) Json.parse(reader); + } + } catch (ParseException | IOException ex) { + throw new RuntimeException(ex.getMessage(), ex); + } + + name = (String) json.get("name"); + dark = Boolean.parseBoolean((String) json.get("dark")); + base = (String) json.get("base"); + if (base == null) { + base = StringUtils.EMPTY; + } + + Map icons = (Map) json.get("icons"); + + for (Map.Entry icon : icons.entrySet()) { + applyIcon(icon.getKey(), icon.getValue()); + } + + } + + private void applyIcon(String key, Object value) { + if (value instanceof String) { + dealWithIconString(key, (String) value); + } else if (value instanceof Map) { + dealWithIconMap(key, (Map) value); + } + } + + private void dealWithIconString(String key, String value) { + if (IconManager.isSvgIcon(value)) { + // 默认字符串提供正常图和灰化图 + addIcon(new PluginSvgIconSource(key, + base + value, + IconManager.findDisablePath(base + value), + null + )); + } else if (IconManager.isImageIcon(value)) { + addIcon(new PluginImageIconSource(key, base + value)); + } + // 其他无法识别格式不处理 + } + + + /** + * 处理object形式的icon配置 + */ + private void dealWithIconMap(String key, Map value) { + String normalPath = (String) value.get(IconType.normal.name()); + String disablePath = (String) value.get(IconType.disable.name()); + String whitePath = (String) value.get(IconType.white.name()); + // 暂不支持混合格式,每个id的格式需要保持一致 + if (IconManager.isSvgIcon(normalPath)) { + addIcon(new PluginSvgIconSource(key, + base + normalPath, + StringUtils.isNotBlank(disablePath) ? base + disablePath : null, + StringUtils.isNotBlank(whitePath) ? base + whitePath : null + )); + } else if (IconManager.isImageIcon(normalPath)) { + addIcon(new PluginImageIconSource(key, + base + normalPath, + StringUtils.isNotBlank(disablePath) ? base + disablePath : null, + StringUtils.isNotBlank(whitePath) ? base + whitePath : null + )); + } + } + + /** + * 根据 map 注册图标 + * @param iconId2Path key: id, value: icon path + */ + public void addIconWithMap(Map iconId2Path) { + for (Map.Entry entry: iconId2Path.entrySet()) { + if (PluginIconManager.isSvgIcon(entry.getValue())) { + addIcon(new PluginSvgIconSource(entry.getKey(), entry.getValue())); + } else if (PluginIconManager.isImageIcon(entry.getValue())) { + addIcon(new PluginImageIconSource(entry.getKey(), entry.getValue())); + } + } + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PluginIconSet that = (PluginIconSet) o; + return Objects.equals(name, that.name); + } + + @Override + public int hashCode() { + return Objects.hashCode(name); + } +} diff --git a/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginLazyIcon.java b/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginLazyIcon.java new file mode 100644 index 0000000000..c6ac211335 --- /dev/null +++ b/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginLazyIcon.java @@ -0,0 +1,129 @@ +package com.fine.theme.icon.plugin; + +import com.fine.theme.icon.DisabledIcon; +import com.fine.theme.icon.IconManager; +import com.fine.theme.icon.IconType; +import com.fine.theme.icon.Identifiable; +import com.fine.theme.icon.WhiteIcon; +import com.fr.design.fun.impl.AbstractLazyIconProvider; +import org.jetbrains.annotations.NotNull; + +import javax.swing.Icon; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Graphics; +import java.util.StringJoiner; + +import static com.fine.theme.utils.FineUIScale.scale; + +public class PluginLazyIcon implements Identifiable, DisabledIcon, WhiteIcon, Icon { + @NotNull + private final String id; + + private final Dimension dimension; + + private final IconType type; + + private final String source; + + /** + * + * @param source {@link AbstractLazyIconProvider#source()} + * @param id + */ + public PluginLazyIcon(@NotNull final String source, @NotNull final String id) { + this.id = id; + this.dimension = IconManager.DEFAULT_DIMENSION; + this.type = IconType.normal; + this.source = source; + } + + public PluginLazyIcon(@NotNull final String source, @NotNull final String id, int side) { + this.id = id; + this.dimension = new Dimension(side, side); + this.type = IconType.normal; + this.source = source; + } + + public PluginLazyIcon(@NotNull final String source, @NotNull final String id, @NotNull Dimension dimension) { + this.id = id; + this.dimension = dimension; + this.type = IconType.normal; + this.source = source; + } + + private PluginLazyIcon(@NotNull final String source, @NotNull final String id, @NotNull IconType type) { + this.id = id; + this.dimension = IconManager.DEFAULT_DIMENSION; + this.type = type; + this.source = source; + } + + public PluginLazyIcon(@NotNull final String source, @NotNull final String id, @NotNull Dimension dimension, @NotNull IconType type) { + this.id = id; + this.dimension = dimension; + this.type = type; + this.source = source; + } + + + @NotNull + @Override + public String getId() { + return id; + } + + @Override + public void paintIcon(@NotNull final Component c, @NotNull final Graphics g, final int x, final int y) { + getIcon().paintIcon(c, g, x, y); + } + + @Override + public int getIconWidth() { + return scale(dimension.width); + } + + @Override + public int getIconHeight() { + return scale(dimension.height); + } + + + @NotNull + public I getIcon() { + return PluginIconManager.getIcon(source, getId(), dimension, type); + } + + /** + * 创建一份灰化图标 + * + * @return 灰化图标 + */ + @NotNull + @Override + public Icon disabled() { + return new PluginLazyIcon(source, getId(), dimension, IconType.disable); + } + + /** + * 创建一份白化图标 + * + * @return 白化图标 + */ + @NotNull + @Override + public Icon white() { + return new PluginLazyIcon(source, getId(), dimension, IconType.white); + } + + + @Override + public String toString() { + return new StringJoiner(", ", PluginLazyIcon.class.getSimpleName() + "[", "]") + .add("source='" + source + "'") + .add("id='" + id + "'") + .add("size=" + "[w=" + scale(dimension.width) + ",h=" + scale(dimension.height) + "]") + .add("type=" + type) + .toString(); + } +} diff --git a/designer-base/src/main/java/com/fr/design/fun/LazyIconProvider.java b/designer-base/src/main/java/com/fr/design/fun/LazyIconProvider.java new file mode 100644 index 0000000000..93989775fe --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/fun/LazyIconProvider.java @@ -0,0 +1,68 @@ +package com.fr.design.fun; + +import com.fr.stable.fun.mark.Mutable; + +import java.util.Map; + +/** + * 插件图标适配接口 + * + * @author lemon + * @since + * Created on + */ +public interface LazyIconProvider extends Mutable { + String MARK_STRING = "LazyIconProvider"; + + int CURRENT_LEVEL = 1; + + /** + * 自定义,icon 来源标识 + * + * @return 来源标识 + */ + String source(); + + /** + * json 文件路径 + * + * @return 图标注册 json 路径 + */ + String jsonPath(); + + /** + * 图标所属主题分类 + * + * @return 主题类别 + */ + THEME themeCategory(); + + /** + * 构建需要注册的图标 key: id, value: icon path + * @return map + */ + Map iconId2Path(); + + /** + * 图标主题 + */ + enum THEME { + + /** + * light_icon + */ + LIGHT_ICON("light_icon"), + + /** + * dark_icon + */ + DARK_ICON("dark_icon") + ; + + final String category; + THEME(String category) { + this.category = category; + } + } + +} diff --git a/designer-base/src/main/java/com/fr/design/fun/impl/AbstractLazyIconProvider.java b/designer-base/src/main/java/com/fr/design/fun/impl/AbstractLazyIconProvider.java new file mode 100644 index 0000000000..53002c2705 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/fun/impl/AbstractLazyIconProvider.java @@ -0,0 +1,71 @@ +package com.fr.design.fun.impl; + +import com.fr.design.fun.LazyIconProvider; +import com.fr.stable.fun.impl.AbstractProvider; +import com.fr.stable.fun.mark.API; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.Map; + + +/** + * 插件图标 LazyIcon 加载适配抽象类 + * + * @author lemon + * @since + * Created on + */ +@API(level = LazyIconProvider.CURRENT_LEVEL) +public class AbstractLazyIconProvider extends AbstractProvider implements LazyIconProvider { + + /** + * 当前接口的API等级,用于判断是否需要升级插件 + * @return API等级 + */ + @Override + public int currentAPILevel() { + return CURRENT_LEVEL; + } + + /** + * 区分插件 + * + * @return 插件 id + */ + @Override + public String source() { + throw new RuntimeException("source is blank"); + } + + /** + * 通过 json 注册图标 + * + * @return 图标注册 json 路径 + */ + @Override + public String jsonPath() { + return null; + } + + /** + * 图标主题 {@link THEME} + * + * @return 主题类别 + */ + @Override + public THEME themeCategory() { + return null; + } + + /** + * 直接注册图标:key 是 icon id, value 是 icon path + * + * @return map + */ + @Override + public Map iconId2Path() { + return null; + } + +} From e2f37f8d7263a899b2ea8e03ad38b7a9217476f8 Mon Sep 17 00:00:00 2001 From: lemon Date: Fri, 23 Aug 2024 17:14:53 +0800 Subject: [PATCH 02/10] =?UTF-8?q?REPORT-127437=20feat:=E9=80=82=E9=85=8D?= =?UTF-8?q?=E6=8F=92=E4=BB=B6=E5=9B=BE=E6=A0=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fine/theme/icon/plugin/PluginIconSet.java | 28 ++++---- .../theme/icon/plugin/PluginLazyIcon.java | 14 +++- .../fine/theme/light/ui/laf/FineDarkLaf.java | 3 + .../com/fine/theme/light/ui/laf/FineLaf.java | 72 +++++++++++++++++++ .../fine/theme/light/ui/laf/FineLightLaf.java | 2 + .../com/fr/design/fun/LazyIconProvider.java | 4 +- .../fun/impl/AbstractLazyIconProvider.java | 4 +- 7 files changed, 107 insertions(+), 20 deletions(-) diff --git a/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginIconSet.java b/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginIconSet.java index 151322d725..e2e2c13354 100644 --- a/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginIconSet.java +++ b/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginIconSet.java @@ -1,8 +1,10 @@ package com.fine.theme.icon.plugin; import com.fine.theme.icon.AbstractIconSet; -import com.fine.theme.icon.IconManager; import com.fine.theme.icon.IconType; +import com.fine.theme.icon.UrlIconResource; +import com.fine.theme.icon.img.ImageIconSource; +import com.fine.theme.icon.svg.SvgIconSource; import com.formdev.flatlaf.json.Json; import com.formdev.flatlaf.json.ParseException; import com.fr.stable.StringUtils; @@ -27,7 +29,7 @@ public class PluginIconSet extends AbstractIconSet { private String base; - public PluginIconSet(PluginUrlIconResource resource, Map iconId2Path) { + public PluginIconSet(UrlIconResource resource, Map iconId2Path) { addIconWithMap(iconId2Path); if (resource.getPath() == null) { @@ -66,15 +68,15 @@ public class PluginIconSet extends AbstractIconSet { } private void dealWithIconString(String key, String value) { - if (IconManager.isSvgIcon(value)) { + if (PluginIconManager.isSvgIcon(value)) { // 默认字符串提供正常图和灰化图 - addIcon(new PluginSvgIconSource(key, + addIcon(new SvgIconSource(key, base + value, - IconManager.findDisablePath(base + value), + PluginIconManager.findDisablePath(base + value), null )); - } else if (IconManager.isImageIcon(value)) { - addIcon(new PluginImageIconSource(key, base + value)); + } else if (PluginIconManager.isImageIcon(value)) { + addIcon(new ImageIconSource(key, base + value)); } // 其他无法识别格式不处理 } @@ -88,14 +90,14 @@ public class PluginIconSet extends AbstractIconSet { String disablePath = (String) value.get(IconType.disable.name()); String whitePath = (String) value.get(IconType.white.name()); // 暂不支持混合格式,每个id的格式需要保持一致 - if (IconManager.isSvgIcon(normalPath)) { - addIcon(new PluginSvgIconSource(key, + if (PluginIconManager.isSvgIcon(normalPath)) { + addIcon(new SvgIconSource(key, base + normalPath, StringUtils.isNotBlank(disablePath) ? base + disablePath : null, StringUtils.isNotBlank(whitePath) ? base + whitePath : null )); - } else if (IconManager.isImageIcon(normalPath)) { - addIcon(new PluginImageIconSource(key, + } else if (PluginIconManager.isImageIcon(normalPath)) { + addIcon(new ImageIconSource(key, base + normalPath, StringUtils.isNotBlank(disablePath) ? base + disablePath : null, StringUtils.isNotBlank(whitePath) ? base + whitePath : null @@ -110,9 +112,9 @@ public class PluginIconSet extends AbstractIconSet { public void addIconWithMap(Map iconId2Path) { for (Map.Entry entry: iconId2Path.entrySet()) { if (PluginIconManager.isSvgIcon(entry.getValue())) { - addIcon(new PluginSvgIconSource(entry.getKey(), entry.getValue())); + addIcon(new SvgIconSource(entry.getKey(), entry.getValue())); } else if (PluginIconManager.isImageIcon(entry.getValue())) { - addIcon(new PluginImageIconSource(entry.getKey(), entry.getValue())); + addIcon(new ImageIconSource(entry.getKey(), entry.getValue())); } } } diff --git a/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginLazyIcon.java b/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginLazyIcon.java index c6ac211335..9cb11e567e 100644 --- a/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginLazyIcon.java +++ b/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginLazyIcon.java @@ -6,6 +6,7 @@ import com.fine.theme.icon.IconType; import com.fine.theme.icon.Identifiable; import com.fine.theme.icon.WhiteIcon; import com.fr.design.fun.impl.AbstractLazyIconProvider; +import com.fr.stable.AssistUtils; import org.jetbrains.annotations.NotNull; import javax.swing.Icon; @@ -16,6 +17,13 @@ import java.util.StringJoiner; import static com.fine.theme.utils.FineUIScale.scale; +/** + * 插件图标加载类 + * + * @author lemon + * @since + * Created on 2024/08/23 + */ public class PluginLazyIcon implements Identifiable, DisabledIcon, WhiteIcon, Icon { @NotNull private final String id; @@ -28,7 +36,7 @@ public class PluginLazyIcon implements Identifiable, DisabledIcon, WhiteIcon, Ic /** * - * @param source {@link AbstractLazyIconProvider#source()} + * @param source {@link AbstractLazyIconProvider#pluginId()} * @param id */ public PluginLazyIcon(@NotNull final String source, @NotNull final String id) { @@ -119,11 +127,11 @@ public class PluginLazyIcon implements Identifiable, DisabledIcon, WhiteIcon, Ic @Override public String toString() { - return new StringJoiner(", ", PluginLazyIcon.class.getSimpleName() + "[", "]") + return AssistUtils.toString(new StringJoiner(", ", PluginLazyIcon.class.getSimpleName() + "[", "]") .add("source='" + source + "'") .add("id='" + id + "'") .add("size=" + "[w=" + scale(dimension.width) + ",h=" + scale(dimension.height) + "]") .add("type=" + type) - .toString(); + .toString()); } } diff --git a/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineDarkLaf.java b/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineDarkLaf.java index e568f5af32..f83edb06d4 100644 --- a/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineDarkLaf.java +++ b/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineDarkLaf.java @@ -4,6 +4,7 @@ import com.fine.swing.ui.layout.Layouts; import com.fine.theme.icon.IconManager; import com.fine.theme.light.ui.FineLightIconSet; import com.formdev.flatlaf.util.UIScale; +import com.fr.design.fun.LazyIconProvider; import com.fr.stable.StringUtils; /** @@ -32,6 +33,8 @@ public class FineDarkLaf extends FineLaf { Layouts.setScaleFactor((float) evt.getNewValue()); } }); + // dark_icon 目前还没适配,先使用 light_icon + insertIconProvider(LazyIconProvider.THEME.LIGHT_ICON); return setup(new FineDarkLaf()); } diff --git a/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLaf.java b/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLaf.java index edb038dd0f..f72f91e92c 100644 --- a/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLaf.java +++ b/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLaf.java @@ -1,9 +1,22 @@ package com.fine.theme.light.ui.laf; +import com.fine.theme.icon.UrlIconResource; +import com.fine.theme.icon.plugin.PluginIconManager; +import com.fine.theme.icon.plugin.PluginIconSet; import com.formdev.flatlaf.FlatLaf; import com.formdev.flatlaf.util.SystemInfo; +import com.fr.design.ExtraDesignClassManager; +import com.fr.design.fun.LazyIconProvider; +import com.fr.general.ComparatorUtils; +import com.fr.general.GeneralContext; +import com.fr.plugin.manage.PluginFilter; +import com.fr.plugin.observer.PluginEvent; +import com.fr.plugin.observer.PluginEventListener; +import com.fr.plugin.observer.PluginEventType; import javax.swing.PopupFactory; +import java.util.Set; +import java.util.function.BiConsumer; /** * Fine designer new look and feel @@ -18,6 +31,21 @@ public abstract class FineLaf extends FlatLaf { private static final String NAME = "FineLaf"; + private static void handlePluginEvent(PluginEvent event, LazyIconProvider.THEME category, + BiConsumer operation) { + Set set = event.getContext().getRuntime().get(LazyIconProvider.MARK_STRING); + dealWithPluginIcon(set, category, operation); + } + + private static void dealWithPluginIcon(Set set, LazyIconProvider.THEME category, + BiConsumer operation) { + for (LazyIconProvider provider : set) { + if (!ComparatorUtils.equals(provider.themeCategory(), category)) { + continue; + } + operation.accept(provider, new PluginIconSet(new UrlIconResource(provider.jsonPath()), provider.iconId2Path())); + } + } @Override public String getName() { @@ -53,4 +81,48 @@ public abstract class FineLaf extends FlatLaf { System.setProperty("flatlaf.menuBarEmbedded", "false"); } } + + /** + * 适配插件图标 Icon + * @param category 图标 Icon 分类 {@link LazyIconProvider.THEME} + */ + public static void insertIconProvider(LazyIconProvider.THEME category) { + Set set = ExtraDesignClassManager.getInstance().getArray(LazyIconProvider.MARK_STRING); + dealWithPluginIcon(set, category, (provider, iconSet) -> PluginIconManager.addSet(provider.pluginId(), iconSet)); + listenerPlugins(category); + } + + private static void listenerPlugins(LazyIconProvider.THEME category) { + //注册插件监听 + PluginFilter filter = context -> context.contain(LazyIconProvider.MARK_STRING); + + PluginEventListener insert = new PluginEventListener() { + @Override + public void on(PluginEvent event) { + handlePluginEvent(event, category, (provider, iconSet) -> PluginIconManager.addSet(provider.pluginId(), iconSet)); + } + }; + + PluginEventListener update = new PluginEventListener() { + @Override + public void on(PluginEvent event) { + handlePluginEvent(event, category, (provider, iconSet) -> PluginIconManager.updateSet(provider.pluginId(), iconSet)); + } + }; + + PluginEventListener remove = new PluginEventListener() { + @Override + public void on(PluginEvent event) { + handlePluginEvent(event, category, (provider, iconSet) -> PluginIconManager.removeSet(provider.pluginId())); + } + }; + + GeneralContext.listenPlugin(PluginEventType.AfterRun, insert, filter); + GeneralContext.listenPlugin(PluginEventType.AfterInstall, insert, filter); + GeneralContext.listenPlugin(PluginEventType.AfterUpdate, update, filter); + GeneralContext.listenPlugin(PluginEventType.AfterActive, update, filter); + GeneralContext.listenPlugin(PluginEventType.AfterForbid, remove, filter); + GeneralContext.listenPlugin(PluginEventType.AfterUninstall, remove, filter); + } + } diff --git a/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLightLaf.java b/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLightLaf.java index 9e95b76f7e..fee8317f93 100644 --- a/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLightLaf.java +++ b/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLightLaf.java @@ -4,6 +4,7 @@ import com.fine.swing.ui.layout.Layouts; import com.fine.theme.icon.IconManager; import com.fine.theme.light.ui.FineLightIconSet; import com.formdev.flatlaf.util.UIScale; +import com.fr.design.fun.LazyIconProvider; import com.fr.stable.StringUtils; /** @@ -32,6 +33,7 @@ public class FineLightLaf extends FineLaf { Layouts.setScaleFactor((float) evt.getNewValue()); } }); + insertIconProvider(LazyIconProvider.THEME.LIGHT_ICON); return setup(new FineLightLaf()); } diff --git a/designer-base/src/main/java/com/fr/design/fun/LazyIconProvider.java b/designer-base/src/main/java/com/fr/design/fun/LazyIconProvider.java index 93989775fe..1a9fc8095d 100644 --- a/designer-base/src/main/java/com/fr/design/fun/LazyIconProvider.java +++ b/designer-base/src/main/java/com/fr/design/fun/LazyIconProvider.java @@ -17,11 +17,11 @@ public interface LazyIconProvider extends Mutable { int CURRENT_LEVEL = 1; /** - * 自定义,icon 来源标识 + * 插件 id,icon 来源标识 * * @return 来源标识 */ - String source(); + String pluginId(); /** * json 文件路径 diff --git a/designer-base/src/main/java/com/fr/design/fun/impl/AbstractLazyIconProvider.java b/designer-base/src/main/java/com/fr/design/fun/impl/AbstractLazyIconProvider.java index 53002c2705..6da1316497 100644 --- a/designer-base/src/main/java/com/fr/design/fun/impl/AbstractLazyIconProvider.java +++ b/designer-base/src/main/java/com/fr/design/fun/impl/AbstractLazyIconProvider.java @@ -34,8 +34,8 @@ public class AbstractLazyIconProvider extends AbstractProvider implements LazyIc * @return 插件 id */ @Override - public String source() { - throw new RuntimeException("source is blank"); + public String pluginId() { + throw new RuntimeException("plugin id is blank"); } /** From c62885a7044e072f835d0d1167cef1f36827c42d Mon Sep 17 00:00:00 2001 From: lemon Date: Fri, 23 Aug 2024 18:15:32 +0800 Subject: [PATCH 03/10] =?UTF-8?q?REPORT-127437=20feat:=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E4=BB=A3=E7=A0=81,=E5=A2=9E=E5=8A=A0=20mapSet?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../theme/icon/plugin/PluginIconManager.java | 54 +++++++++++-------- ...ginIconSet.java => PluginJsonIconSet.java} | 25 ++------- .../theme/icon/plugin/PluginLazyIcon.java | 4 +- .../theme/icon/plugin/PluginMapIconSet.java | 54 +++++++++++++++++++ .../fine/theme/light/ui/laf/FineDarkLaf.java | 4 +- .../com/fine/theme/light/ui/laf/FineLaf.java | 25 ++++++--- .../fine/theme/light/ui/laf/FineLightLaf.java | 2 +- 7 files changed, 112 insertions(+), 56 deletions(-) rename designer-base/src/main/java/com/fine/theme/icon/plugin/{PluginIconSet.java => PluginJsonIconSet.java} (82%) create mode 100644 designer-base/src/main/java/com/fine/theme/icon/plugin/PluginMapIconSet.java diff --git a/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginIconManager.java b/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginIconManager.java index 8648396f75..e0f6a822d2 100644 --- a/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginIconManager.java +++ b/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginIconManager.java @@ -8,6 +8,7 @@ import com.fine.theme.icon.LazyIcon; import com.fr.base.extension.FileExtension; import com.fr.general.IOUtils; import com.fr.log.FineLoggerFactory; +import com.fr.nx.app.web.out.widget.utils.CollectionUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -15,7 +16,9 @@ import javax.swing.Icon; import java.awt.Dimension; import java.lang.ref.WeakReference; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; /** * 管理插件图标集 @@ -28,8 +31,8 @@ public class PluginIconManager { public static final String ICON_DISABLE_SUFFIX = "_disable"; public static final Dimension DEFAULT_DIMENSION = new Dimension(16, 16); - private static final Map SOURCE_ICON_MAPS = new HashMap<>(2); - private static final HashMap>> CACHE = new HashMap<>(); + private static final Map> SOURCE_ICON_MAPS = new ConcurrentHashMap<>(2); + private static final Map>> CACHE = new ConcurrentHashMap<>(); /** @@ -39,10 +42,12 @@ public class PluginIconManager { * @return 图标集 */ public static IconSet getSet(String source, String id) { - IconSet set = SOURCE_ICON_MAPS.get(source); + List sets = SOURCE_ICON_MAPS.get(source); - if (set != null && set.getId().equals(id)) { - return set; + for (IconSet set : sets) { + if (set != null && set.getId().equals(id)) { + return set; + } } throw new IconException("[PluginIconManager] Can not find icon set by id: " + id); } @@ -51,25 +56,26 @@ public class PluginIconManager { * 添加图标集 * * @param source 插件 - * @param set 图标集 + * @param sets 图标集 */ - public static void addSet(@NotNull String source, @NotNull IconSet set) { + public static void addSet(@NotNull String source, @NotNull List sets) { if (SOURCE_ICON_MAPS.containsKey(source)) { FineLoggerFactory.getLogger().warn("[PluginIconManager] plugin:{} icon set already exists: " + source); } - SOURCE_ICON_MAPS.put(source, set); + SOURCE_ICON_MAPS.put(source, sets); clearCacheBySource(source); } + /** * 更新指定插件图标集 * * @param source 插件 - * @param set 图标集 + * @param sets 图标集 */ - public static void updateSet(@NotNull String source, @NotNull IconSet set) { - SOURCE_ICON_MAPS.put(source, set); - clearCacheBySource(source); + public static void updateSet(@NotNull String source, @NotNull List sets) { + removeSet(source); + addSet(source, sets); } /** @@ -120,15 +126,17 @@ public class PluginIconManager { final WeakReference reference = sourceCache.get(cacheKey); I icon = reference != null ? (I) reference.get() : null; if (icon == null) { - IconSet set = SOURCE_ICON_MAPS.get(source); - if (set == null) { + List sets = SOURCE_ICON_MAPS.get(source); + if (CollectionUtils.isEmpty(sets)) { return icon; } - Icon f = set.findIcon(id, dimension, type); - if (f != null) { - icon = (I) f; - sourceCache.put(cacheKey, new WeakReference<>(icon)); - CACHE.put(source, sourceCache); + for (IconSet set : sets) { + Icon f = set.findIcon(id, dimension, type); + if (f != null) { + icon = (I) f; + sourceCache.put(cacheKey, new WeakReference<>(icon)); + CACHE.put(source, sourceCache); + } } } return icon; @@ -178,9 +186,11 @@ public class PluginIconManager { * @return 是否存在 */ public static boolean existIcon(String id, String source) { - IconSet set = SOURCE_ICON_MAPS.get(source); - if (set != null && set.getIds().contains(id)) { - return true; + List sets = SOURCE_ICON_MAPS.get(source); + for (IconSet set : sets) { + if (set != null && set.getIds().contains(id)) { + return true; + } } return false; } diff --git a/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginIconSet.java b/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginJsonIconSet.java similarity index 82% rename from designer-base/src/main/java/com/fine/theme/icon/plugin/PluginIconSet.java rename to designer-base/src/main/java/com/fine/theme/icon/plugin/PluginJsonIconSet.java index e2e2c13354..66c758f825 100644 --- a/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginIconSet.java +++ b/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginJsonIconSet.java @@ -18,20 +18,17 @@ import java.util.Map; import java.util.Objects; /** - * 插件图标集 + * 插件 json 图标集 * * @author lemon * @since * Created on 2024/08/20 */ -public class PluginIconSet extends AbstractIconSet { +public class PluginJsonIconSet extends AbstractIconSet { private String base; - - public PluginIconSet(UrlIconResource resource, Map iconId2Path) { - addIconWithMap(iconId2Path); - + public PluginJsonIconSet(UrlIconResource resource) { if (resource.getPath() == null) { return; } @@ -105,20 +102,6 @@ public class PluginIconSet extends AbstractIconSet { } } - /** - * 根据 map 注册图标 - * @param iconId2Path key: id, value: icon path - */ - public void addIconWithMap(Map iconId2Path) { - for (Map.Entry entry: iconId2Path.entrySet()) { - if (PluginIconManager.isSvgIcon(entry.getValue())) { - addIcon(new SvgIconSource(entry.getKey(), entry.getValue())); - } else if (PluginIconManager.isImageIcon(entry.getValue())) { - addIcon(new ImageIconSource(entry.getKey(), entry.getValue())); - } - } - } - @Override public boolean equals(Object o) { if (this == o) { @@ -127,7 +110,7 @@ public class PluginIconSet extends AbstractIconSet { if (o == null || getClass() != o.getClass()) { return false; } - PluginIconSet that = (PluginIconSet) o; + PluginJsonIconSet that = (PluginJsonIconSet) o; return Objects.equals(name, that.name); } diff --git a/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginLazyIcon.java b/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginLazyIcon.java index 9cb11e567e..8f17242505 100644 --- a/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginLazyIcon.java +++ b/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginLazyIcon.java @@ -127,11 +127,11 @@ public class PluginLazyIcon implements Identifiable, DisabledIcon, WhiteIcon, Ic @Override public String toString() { - return AssistUtils.toString(new StringJoiner(", ", PluginLazyIcon.class.getSimpleName() + "[", "]") + return new StringJoiner(", ", PluginLazyIcon.class.getSimpleName() + "[", "]") .add("source='" + source + "'") .add("id='" + id + "'") .add("size=" + "[w=" + scale(dimension.width) + ",h=" + scale(dimension.height) + "]") .add("type=" + type) - .toString()); + .toString(); } } diff --git a/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginMapIconSet.java b/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginMapIconSet.java new file mode 100644 index 0000000000..fdc32bac63 --- /dev/null +++ b/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginMapIconSet.java @@ -0,0 +1,54 @@ +package com.fine.theme.icon.plugin; + +import com.fine.theme.icon.AbstractIconSet; +import com.fine.theme.icon.img.ImageIconSource; +import com.fine.theme.icon.svg.SvgIconSource; + +import java.util.Map; +import java.util.Objects; + +/** + * 插件 map 图标集 + * + * @author lemon + * @since + * Created on 2024/08/20 + */ +public class PluginMapIconSet extends AbstractIconSet { + + public PluginMapIconSet(Map iconId2Path) { + addIconWithMap(iconId2Path); + } + + + /** + * 根据 map 注册图标 + * @param iconId2Path key: id, value: icon path + */ + public void addIconWithMap(Map iconId2Path) { + for (Map.Entry entry: iconId2Path.entrySet()) { + if (PluginIconManager.isSvgIcon(entry.getValue())) { + addIcon(new SvgIconSource(entry.getKey(), entry.getValue())); + } else if (PluginIconManager.isImageIcon(entry.getValue())) { + addIcon(new ImageIconSource(entry.getKey(), entry.getValue())); + } + } + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PluginMapIconSet that = (PluginMapIconSet) o; + return Objects.equals(name, that.name); + } + + @Override + public int hashCode() { + return Objects.hashCode(name); + } +} diff --git a/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineDarkLaf.java b/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineDarkLaf.java index f83edb06d4..f06d8ee888 100644 --- a/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineDarkLaf.java +++ b/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineDarkLaf.java @@ -27,14 +27,14 @@ public class FineDarkLaf extends FineLaf { */ public static boolean setup() { IconManager.addSet(new FineLightIconSet()); + // dark_icon 目前还没适配,先使用 light_icon + insertIconProvider(LazyIconProvider.THEME.LIGHT_ICON); Layouts.setScaleFactor(UIScale.getUserScaleFactor()); UIScale.addPropertyChangeListener(evt -> { if (StringUtils.equals(evt.getPropertyName(), USER_SCALE_FACTOR)) { Layouts.setScaleFactor((float) evt.getNewValue()); } }); - // dark_icon 目前还没适配,先使用 light_icon - insertIconProvider(LazyIconProvider.THEME.LIGHT_ICON); return setup(new FineDarkLaf()); } diff --git a/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLaf.java b/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLaf.java index f72f91e92c..f28f1e11d0 100644 --- a/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLaf.java +++ b/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLaf.java @@ -1,8 +1,10 @@ package com.fine.theme.light.ui.laf; +import com.fine.theme.icon.IconSet; import com.fine.theme.icon.UrlIconResource; import com.fine.theme.icon.plugin.PluginIconManager; -import com.fine.theme.icon.plugin.PluginIconSet; +import com.fine.theme.icon.plugin.PluginJsonIconSet; +import com.fine.theme.icon.plugin.PluginMapIconSet; import com.formdev.flatlaf.FlatLaf; import com.formdev.flatlaf.util.SystemInfo; import com.fr.design.ExtraDesignClassManager; @@ -15,6 +17,8 @@ import com.fr.plugin.observer.PluginEventListener; import com.fr.plugin.observer.PluginEventType; import javax.swing.PopupFactory; +import java.util.ArrayList; +import java.util.List; import java.util.Set; import java.util.function.BiConsumer; @@ -32,18 +36,23 @@ public abstract class FineLaf extends FlatLaf { private static final String NAME = "FineLaf"; private static void handlePluginEvent(PluginEvent event, LazyIconProvider.THEME category, - BiConsumer operation) { + BiConsumer> operation) { Set set = event.getContext().getRuntime().get(LazyIconProvider.MARK_STRING); dealWithPluginIcon(set, category, operation); } private static void dealWithPluginIcon(Set set, LazyIconProvider.THEME category, - BiConsumer operation) { + BiConsumer> operation) { for (LazyIconProvider provider : set) { if (!ComparatorUtils.equals(provider.themeCategory(), category)) { continue; } - operation.accept(provider, new PluginIconSet(new UrlIconResource(provider.jsonPath()), provider.iconId2Path())); + List iconSets = new ArrayList<>(); + PluginJsonIconSet jsonIconSet = new PluginJsonIconSet(new UrlIconResource(provider.jsonPath())); + iconSets.add(jsonIconSet); + PluginMapIconSet mapIconSet = new PluginMapIconSet(provider.iconId2Path()); + iconSets.add(mapIconSet); + operation.accept(provider, iconSets); } } @@ -88,7 +97,7 @@ public abstract class FineLaf extends FlatLaf { */ public static void insertIconProvider(LazyIconProvider.THEME category) { Set set = ExtraDesignClassManager.getInstance().getArray(LazyIconProvider.MARK_STRING); - dealWithPluginIcon(set, category, (provider, iconSet) -> PluginIconManager.addSet(provider.pluginId(), iconSet)); + dealWithPluginIcon(set, category, (provider, iconSets) -> PluginIconManager.addSet(provider.pluginId(), iconSets)); listenerPlugins(category); } @@ -99,21 +108,21 @@ public abstract class FineLaf extends FlatLaf { PluginEventListener insert = new PluginEventListener() { @Override public void on(PluginEvent event) { - handlePluginEvent(event, category, (provider, iconSet) -> PluginIconManager.addSet(provider.pluginId(), iconSet)); + handlePluginEvent(event, category, (provider, iconSets) -> PluginIconManager.addSet(provider.pluginId(), iconSets)); } }; PluginEventListener update = new PluginEventListener() { @Override public void on(PluginEvent event) { - handlePluginEvent(event, category, (provider, iconSet) -> PluginIconManager.updateSet(provider.pluginId(), iconSet)); + handlePluginEvent(event, category, (provider, iconSets) -> PluginIconManager.updateSet(provider.pluginId(), iconSets)); } }; PluginEventListener remove = new PluginEventListener() { @Override public void on(PluginEvent event) { - handlePluginEvent(event, category, (provider, iconSet) -> PluginIconManager.removeSet(provider.pluginId())); + handlePluginEvent(event, category, (provider, iconSets) -> PluginIconManager.removeSet(provider.pluginId())); } }; diff --git a/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLightLaf.java b/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLightLaf.java index fee8317f93..08a0602d62 100644 --- a/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLightLaf.java +++ b/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLightLaf.java @@ -27,13 +27,13 @@ public class FineLightLaf extends FineLaf { */ public static boolean setup() { IconManager.addSet(new FineLightIconSet()); + insertIconProvider(LazyIconProvider.THEME.LIGHT_ICON); Layouts.setScaleFactor(UIScale.getUserScaleFactor()); UIScale.addPropertyChangeListener(evt -> { if (StringUtils.equals(evt.getPropertyName(), USER_SCALE_FACTOR)) { Layouts.setScaleFactor((float) evt.getNewValue()); } }); - insertIconProvider(LazyIconProvider.THEME.LIGHT_ICON); return setup(new FineLightLaf()); } From 429b1af7ad00312b90b0c2be6112903f06f2ed5f Mon Sep 17 00:00:00 2001 From: "Destiny.Lin" Date: Mon, 26 Aug 2024 15:13:15 +0800 Subject: [PATCH 04/10] =?UTF-8?q?=E6=97=A0jira=E4=BB=BB=E5=8A=A1=EF=BC=8C?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=89=93=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fanruan/boot/env/DesignEnvComponent.java | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/designer-realize/src/main/java/com/fanruan/boot/env/DesignEnvComponent.java b/designer-realize/src/main/java/com/fanruan/boot/env/DesignEnvComponent.java index 7c9350430a..551455aeab 100644 --- a/designer-realize/src/main/java/com/fanruan/boot/env/DesignEnvComponent.java +++ b/designer-realize/src/main/java/com/fanruan/boot/env/DesignEnvComponent.java @@ -239,27 +239,27 @@ public class DesignEnvComponent { * ----------- logger -------- */ private void startLogger() { - String realPath = Carina.properties(LoggerProperties.class).getXml(); - URI uri = Log4jUtils.buildUserConfigURI(realPath); + URI uri = Log4jUtils.buildUserConfigURI(StringUtils.EMPTY); FRLogger.getLogger().config(uri); // 日志配置更新的监听在FRLogger里面,fbp去掉了但是设计器本地还是需要这个监听的,初始化的时候监听一下 listenConfig(); } private void listenConfig() { - ValidateConfigManger.getInstance().registerListener(new ConfigChangeListener() { - - @Override - public boolean accept(Class configClass) { - return configClass.equals(Log4jConfig.class); - } - - @Override - public void change() { - // The root logger is the topmost logger with a name of "" (the empty string). - Configurator.setAllLevels("", Log4jConfig.getInstance().getRootLevel()); - } - }); +// 等fbp改完,现在先配合打包注释掉 +// ValidateConfigManger.getInstance().registerListener(new ConfigChangeListener() { +// +// @Override +// public boolean accept(Class configClass) { +// return configClass.equals(Log4jConfig.class); +// } +// +// @Override +// public void change() { +// // The root logger is the topmost logger with a name of "" (the empty string). +// Configurator.setAllLevels("", Log4jConfig.getInstance().getRootLevel()); +// } +// }); } From 874b67c1151583445ca8f63548b5bb8665c47ea1 Mon Sep 17 00:00:00 2001 From: "Destiny.Lin" Date: Mon, 26 Aug 2024 15:14:32 +0800 Subject: [PATCH 05/10] =?UTF-8?q?=E6=97=A0jira=E4=BB=BB=E5=8A=A1=EF=BC=8C?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=89=93=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/fanruan/boot/env/DesignEnvComponent.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/designer-realize/src/main/java/com/fanruan/boot/env/DesignEnvComponent.java b/designer-realize/src/main/java/com/fanruan/boot/env/DesignEnvComponent.java index 551455aeab..95bcc301aa 100644 --- a/designer-realize/src/main/java/com/fanruan/boot/env/DesignEnvComponent.java +++ b/designer-realize/src/main/java/com/fanruan/boot/env/DesignEnvComponent.java @@ -246,7 +246,7 @@ public class DesignEnvComponent { } private void listenConfig() { -// 等fbp改完,现在先配合打包注释掉 +/// 等fbp改完,现在先配合打包注释掉 // ValidateConfigManger.getInstance().registerListener(new ConfigChangeListener() { // // @Override From 78b22dba5dce73cafd71bc015a7b8fac6e6da7c3 Mon Sep 17 00:00:00 2001 From: "Destiny.Lin" Date: Mon, 26 Aug 2024 15:28:52 +0800 Subject: [PATCH 06/10] =?UTF-8?q?=E6=97=A0jira=E4=BB=BB=E5=8A=A1=EF=BC=8C?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=89=93=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/fanruan/boot/env/DesignFunctionComponent.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/designer-realize/src/main/java/com/fanruan/boot/env/DesignFunctionComponent.java b/designer-realize/src/main/java/com/fanruan/boot/env/DesignFunctionComponent.java index 6c584ca3a3..63de9d0d27 100644 --- a/designer-realize/src/main/java/com/fanruan/boot/env/DesignFunctionComponent.java +++ b/designer-realize/src/main/java/com/fanruan/boot/env/DesignFunctionComponent.java @@ -7,7 +7,7 @@ import com.fanruan.carina.annotions.Start; import com.fanruan.messenger.ums.config.email.FineEmailSecurityProviderImpl; import com.fr.base.email.EmailCenter; import com.fr.base.email.impl.EmailAccountManagerImpl; -import com.fr.base.email.impl.FREmailDispatcherImpl; +import com.fr.base.email.impl.EmailDispatcherImpl; import com.fr.base.email.impl.FineEmailExtensionProviderImpl; import com.fr.base.email.impl.FineEmailResourceProviderImpl; import com.fr.base.email.provider.FineEmailExtensionProvider; @@ -78,7 +78,7 @@ public class DesignFunctionComponent { fineEmailExtensionProvider, fineEmailResourceProvider, new FineEmailSecurityProviderImpl()); - EmailCenter.setDispatcher(new FREmailDispatcherImpl()); + EmailCenter.setDispatcher(new EmailDispatcherImpl()); EmailCenter.setAccountManager(new EmailAccountManagerImpl()); EmailTaskManagement.getInstance().start(); } From 91d3d558fb7a292174206eb031c6efa41d343fa0 Mon Sep 17 00:00:00 2001 From: lemon Date: Fri, 30 Aug 2024 11:51:52 +0800 Subject: [PATCH 07/10] =?UTF-8?q?REPORT-127437=20fix:=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E9=80=BB=E8=BE=91=EF=BC=8C=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E8=B7=9F=E8=AE=BE=E8=AE=A1=E5=99=A8=E5=85=B1=E7=94=A8=20icon?= =?UTF-8?q?=20=E5=8A=A0=E8=BD=BD=E6=96=B9=E5=BC=8F=EF=BC=8C=E8=B0=83?= =?UTF-8?q?=E6=95=B4=E6=8F=92=E4=BB=B6=20icon=20=E5=92=8C=20set=20?= =?UTF-8?q?=E7=9A=84=20id=20=E6=A0=87=E8=AF=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/fine/theme/icon/IconManager.java | 33 ++- .../theme/icon/plugin/PluginIconManager.java | 223 ------------------ .../theme/icon/plugin/PluginJsonIconSet.java | 113 +-------- .../theme/icon/plugin/PluginLazyIcon.java | 137 ----------- .../theme/icon/plugin/PluginListIconSet.java | 57 +++++ .../theme/icon/plugin/PluginMapIconSet.java | 54 ----- .../fine/theme/light/ui/laf/FineDarkLaf.java | 5 +- .../com/fine/theme/light/ui/laf/FineLaf.java | 57 ++--- .../fine/theme/light/ui/laf/FineLightLaf.java | 3 +- .../com/fr/design/fun/LazyIconProvider.java | 42 ++-- .../fun/impl/AbstractLazyIconProvider.java | 19 +- 11 files changed, 142 insertions(+), 601 deletions(-) delete mode 100644 designer-base/src/main/java/com/fine/theme/icon/plugin/PluginIconManager.java delete mode 100644 designer-base/src/main/java/com/fine/theme/icon/plugin/PluginLazyIcon.java create mode 100644 designer-base/src/main/java/com/fine/theme/icon/plugin/PluginListIconSet.java delete mode 100644 designer-base/src/main/java/com/fine/theme/icon/plugin/PluginMapIconSet.java diff --git a/designer-base/src/main/java/com/fine/theme/icon/IconManager.java b/designer-base/src/main/java/com/fine/theme/icon/IconManager.java index aa2ef8b173..86506c8475 100644 --- a/designer-base/src/main/java/com/fine/theme/icon/IconManager.java +++ b/designer-base/src/main/java/com/fine/theme/icon/IconManager.java @@ -3,6 +3,7 @@ package com.fine.theme.icon; import com.fr.base.extension.FileExtension; import com.fr.general.IOUtils; import com.fr.log.FineLoggerFactory; +import com.fr.nx.app.web.out.widget.utils.CollectionUtils; import com.fr.third.errorprone.annotations.Immutable; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -10,8 +11,10 @@ import org.jetbrains.annotations.Nullable; import javax.swing.Icon; import java.awt.Dimension; import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; /** * 图标管理器 @@ -29,8 +32,8 @@ public class IconManager { public static final String ICON_DISABLE_SUFFIX = "_disable"; public static final Dimension DEFAULT_DIMENSION = new Dimension(16, 16); - private static final ArrayList ICON_SETS = new ArrayList<>(2); - private static final HashMap> CACHE = new HashMap<>(64); + private static final CopyOnWriteArrayList ICON_SETS = new CopyOnWriteArrayList<>(); + private static final Map> CACHE = new ConcurrentHashMap<>(64); /** @@ -123,6 +126,28 @@ public class IconManager { return id + "_" + dimension.width + "_" + dimension.height + "_" + type; } + /** + * 批量添加图标集 + * + * @param sets 图标集 + */ + public static void addSet(@NotNull List sets) { + if (CollectionUtils.isEmpty(sets)) { + return; + } + sets.forEach(IconManager::addSet); + } + + /** + * 删除指定 id 图标集 + * + * @param id 图标集ID + */ + public static void removeSet(@NotNull String id) { + ICON_SETS.removeIf(iconSet -> id.equals(iconSet.getId())); + clearCache(); + } + /** * 是否SVG图标格式 * diff --git a/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginIconManager.java b/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginIconManager.java deleted file mode 100644 index e0f6a822d2..0000000000 --- a/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginIconManager.java +++ /dev/null @@ -1,223 +0,0 @@ -package com.fine.theme.icon.plugin; - -import com.fine.theme.icon.IconException; -import com.fine.theme.icon.IconManager; -import com.fine.theme.icon.IconSet; -import com.fine.theme.icon.IconType; -import com.fine.theme.icon.LazyIcon; -import com.fr.base.extension.FileExtension; -import com.fr.general.IOUtils; -import com.fr.log.FineLoggerFactory; -import com.fr.nx.app.web.out.widget.utils.CollectionUtils; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.Icon; -import java.awt.Dimension; -import java.lang.ref.WeakReference; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -/** - * 管理插件图标集 - * - * @author lemon - * @since - * Created on 2024/08/23 - */ -public class PluginIconManager { - - public static final String ICON_DISABLE_SUFFIX = "_disable"; - public static final Dimension DEFAULT_DIMENSION = new Dimension(16, 16); - private static final Map> SOURCE_ICON_MAPS = new ConcurrentHashMap<>(2); - private static final Map>> CACHE = new ConcurrentHashMap<>(); - - - /** - * 获取图标集 - * - * @param id 图标集ID - * @return 图标集 - */ - public static IconSet getSet(String source, String id) { - List sets = SOURCE_ICON_MAPS.get(source); - - for (IconSet set : sets) { - if (set != null && set.getId().equals(id)) { - return set; - } - } - throw new IconException("[PluginIconManager] Can not find icon set by id: " + id); - } - - /** - * 添加图标集 - * - * @param source 插件 - * @param sets 图标集 - */ - public static void addSet(@NotNull String source, @NotNull List sets) { - if (SOURCE_ICON_MAPS.containsKey(source)) { - FineLoggerFactory.getLogger().warn("[PluginIconManager] plugin:{} icon set already exists: " + source); - } - SOURCE_ICON_MAPS.put(source, sets); - clearCacheBySource(source); - } - - - /** - * 更新指定插件图标集 - * - * @param source 插件 - * @param sets 图标集 - */ - public static void updateSet(@NotNull String source, @NotNull List sets) { - removeSet(source); - addSet(source, sets); - } - - /** - * 删除指定插件图标集 - * - * @param source 插件 - */ - public static void removeSet(@NotNull String source) { - SOURCE_ICON_MAPS.remove(source); - clearCacheBySource(source); - } - - /** - * 根据图标ID获取图标 - *

- * 查找路径 - * 1)查找图集图标 - * 2)路径为图片图标,从路径再查找 - * 3)提供默认svg图标 - * - * @param id 图标ID - * @param 图标类型 - * @return 图标 - */ - @NotNull - public static I getIcon(@NotNull String source, @NotNull final String id, @NotNull Dimension dimension, @NotNull IconType type) { - Icon icon = findIcon(source, id, dimension, type); - if (icon == null) { - // 只有找不到再进行其他fallback,提升效率 - if (IconManager.isImageIcon(id)) { - return (I) fallbackLegacyIcon(id); - } else { - FineLoggerFactory.getLogger().warn("[PluginIconManager] Can not find icon by id: " + id); - return (I) new LazyIcon("default"); - } - } - return (I) icon; - } - - private static Icon fallbackLegacyIcon(String id) { - return IOUtils.readIcon(id); - } - - @Nullable - private static I findIcon(String source, String id, Dimension dimension, IconType type) { - String cacheKey = genCacheKey(source, id, dimension, type); - HashMap> sourceCache = CACHE.getOrDefault(cacheKey, new HashMap<>(64)); - final WeakReference reference = sourceCache.get(cacheKey); - I icon = reference != null ? (I) reference.get() : null; - if (icon == null) { - List sets = SOURCE_ICON_MAPS.get(source); - if (CollectionUtils.isEmpty(sets)) { - return icon; - } - for (IconSet set : sets) { - Icon f = set.findIcon(id, dimension, type); - if (f != null) { - icon = (I) f; - sourceCache.put(cacheKey, new WeakReference<>(icon)); - CACHE.put(source, sourceCache); - } - } - } - return icon; - } - - - /** - * 生成缓存key - * - * @param id id - * @param dimension 尺寸 - * @param type 图标类型 - * @return 缓存key - */ - public static @NotNull String genCacheKey(String source, String id, Dimension dimension, IconType type) { - if (DEFAULT_DIMENSION.equals(dimension)) { - return source + "_" + id + "_" + type; - } - return source + "_" + id + "_" + dimension.width + "_" + dimension.height + "_" + type; - } - - /** - * 是否SVG图标格式 - * - * @param path 路径 - * @return 是否SVG图标格式 - */ - public static boolean isSvgIcon(String path) { - return FileExtension.SVG.matchExtension(path); - } - - /** - * 是否支持的图片图标格式,目前只支持png和jpg - * - * @param path 路径 - * @return 是否支持的图片图标格式 - */ - public static boolean isImageIcon(String path) { - return FileExtension.PNG.matchExtension(path) - || FileExtension.JPG.matchExtension(path); - } - - /** - * 判断是否存在指定id的icon,非io读取行为,而是从已注册的sourceMap中遍历判断 - * - * @param id id - * @return 是否存在 - */ - public static boolean existIcon(String id, String source) { - List sets = SOURCE_ICON_MAPS.get(source); - for (IconSet set : sets) { - if (set != null && set.getIds().contains(id)) { - return true; - } - } - return false; - } - - /** - * 清理所有缓存 - */ - public static void clearCache() { - CACHE.clear(); - } - - /** - * 清楚指定插件缓存 - * @param source 插件标识 - */ - public static void clearCacheBySource(String source) { - CACHE.remove(source); - } - - /** - * 查找灰化图标 - * - * @param path 原始路径 - * @return 灰化路径 - */ - public static String findDisablePath(String path) { - int i = path.lastIndexOf('.'); - return path.substring(0, i) + ICON_DISABLE_SUFFIX + path.substring(i); - } -} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginJsonIconSet.java b/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginJsonIconSet.java index 66c758f825..75a12c6a43 100644 --- a/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginJsonIconSet.java +++ b/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginJsonIconSet.java @@ -1,121 +1,22 @@ package com.fine.theme.icon.plugin; -import com.fine.theme.icon.AbstractIconSet; -import com.fine.theme.icon.IconType; +import com.fine.theme.icon.JsonIconSet; import com.fine.theme.icon.UrlIconResource; -import com.fine.theme.icon.img.ImageIconSource; -import com.fine.theme.icon.svg.SvgIconSource; -import com.formdev.flatlaf.json.Json; -import com.formdev.flatlaf.json.ParseException; -import com.fr.stable.StringUtils; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.nio.charset.StandardCharsets; -import java.util.Map; -import java.util.Objects; /** * 插件 json 图标集 + * json 格式参考 fine_light.icon.json + * 为了保证 插件之间,插件与设计器 icon id 的唯一性,icons key 值规则参考 {@link PluginListIconSet} * * @author lemon * @since * Created on 2024/08/20 */ -public class PluginJsonIconSet extends AbstractIconSet { - - private String base; - - public PluginJsonIconSet(UrlIconResource resource) { - if (resource.getPath() == null) { - return; - } - Map json; - try (InputStream in = resource.getInputStream()) { - try (Reader reader = new InputStreamReader(in, StandardCharsets.UTF_8)) { - json = (Map) Json.parse(reader); - } - } catch (ParseException | IOException ex) { - throw new RuntimeException(ex.getMessage(), ex); - } - - name = (String) json.get("name"); - dark = Boolean.parseBoolean((String) json.get("dark")); - base = (String) json.get("base"); - if (base == null) { - base = StringUtils.EMPTY; - } - - Map icons = (Map) json.get("icons"); - - for (Map.Entry icon : icons.entrySet()) { - applyIcon(icon.getKey(), icon.getValue()); - } - - } +public class PluginJsonIconSet extends JsonIconSet { - private void applyIcon(String key, Object value) { - if (value instanceof String) { - dealWithIconString(key, (String) value); - } else if (value instanceof Map) { - dealWithIconMap(key, (Map) value); - } + public PluginJsonIconSet(String id, UrlIconResource resource) { + super(resource); + this.name = id; } - private void dealWithIconString(String key, String value) { - if (PluginIconManager.isSvgIcon(value)) { - // 默认字符串提供正常图和灰化图 - addIcon(new SvgIconSource(key, - base + value, - PluginIconManager.findDisablePath(base + value), - null - )); - } else if (PluginIconManager.isImageIcon(value)) { - addIcon(new ImageIconSource(key, base + value)); - } - // 其他无法识别格式不处理 - } - - - /** - * 处理object形式的icon配置 - */ - private void dealWithIconMap(String key, Map value) { - String normalPath = (String) value.get(IconType.normal.name()); - String disablePath = (String) value.get(IconType.disable.name()); - String whitePath = (String) value.get(IconType.white.name()); - // 暂不支持混合格式,每个id的格式需要保持一致 - if (PluginIconManager.isSvgIcon(normalPath)) { - addIcon(new SvgIconSource(key, - base + normalPath, - StringUtils.isNotBlank(disablePath) ? base + disablePath : null, - StringUtils.isNotBlank(whitePath) ? base + whitePath : null - )); - } else if (PluginIconManager.isImageIcon(normalPath)) { - addIcon(new ImageIconSource(key, - base + normalPath, - StringUtils.isNotBlank(disablePath) ? base + disablePath : null, - StringUtils.isNotBlank(whitePath) ? base + whitePath : null - )); - } - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - PluginJsonIconSet that = (PluginJsonIconSet) o; - return Objects.equals(name, that.name); - } - - @Override - public int hashCode() { - return Objects.hashCode(name); - } } diff --git a/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginLazyIcon.java b/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginLazyIcon.java deleted file mode 100644 index 8f17242505..0000000000 --- a/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginLazyIcon.java +++ /dev/null @@ -1,137 +0,0 @@ -package com.fine.theme.icon.plugin; - -import com.fine.theme.icon.DisabledIcon; -import com.fine.theme.icon.IconManager; -import com.fine.theme.icon.IconType; -import com.fine.theme.icon.Identifiable; -import com.fine.theme.icon.WhiteIcon; -import com.fr.design.fun.impl.AbstractLazyIconProvider; -import com.fr.stable.AssistUtils; -import org.jetbrains.annotations.NotNull; - -import javax.swing.Icon; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.Graphics; -import java.util.StringJoiner; - -import static com.fine.theme.utils.FineUIScale.scale; - -/** - * 插件图标加载类 - * - * @author lemon - * @since - * Created on 2024/08/23 - */ -public class PluginLazyIcon implements Identifiable, DisabledIcon, WhiteIcon, Icon { - @NotNull - private final String id; - - private final Dimension dimension; - - private final IconType type; - - private final String source; - - /** - * - * @param source {@link AbstractLazyIconProvider#pluginId()} - * @param id - */ - public PluginLazyIcon(@NotNull final String source, @NotNull final String id) { - this.id = id; - this.dimension = IconManager.DEFAULT_DIMENSION; - this.type = IconType.normal; - this.source = source; - } - - public PluginLazyIcon(@NotNull final String source, @NotNull final String id, int side) { - this.id = id; - this.dimension = new Dimension(side, side); - this.type = IconType.normal; - this.source = source; - } - - public PluginLazyIcon(@NotNull final String source, @NotNull final String id, @NotNull Dimension dimension) { - this.id = id; - this.dimension = dimension; - this.type = IconType.normal; - this.source = source; - } - - private PluginLazyIcon(@NotNull final String source, @NotNull final String id, @NotNull IconType type) { - this.id = id; - this.dimension = IconManager.DEFAULT_DIMENSION; - this.type = type; - this.source = source; - } - - public PluginLazyIcon(@NotNull final String source, @NotNull final String id, @NotNull Dimension dimension, @NotNull IconType type) { - this.id = id; - this.dimension = dimension; - this.type = type; - this.source = source; - } - - - @NotNull - @Override - public String getId() { - return id; - } - - @Override - public void paintIcon(@NotNull final Component c, @NotNull final Graphics g, final int x, final int y) { - getIcon().paintIcon(c, g, x, y); - } - - @Override - public int getIconWidth() { - return scale(dimension.width); - } - - @Override - public int getIconHeight() { - return scale(dimension.height); - } - - - @NotNull - public I getIcon() { - return PluginIconManager.getIcon(source, getId(), dimension, type); - } - - /** - * 创建一份灰化图标 - * - * @return 灰化图标 - */ - @NotNull - @Override - public Icon disabled() { - return new PluginLazyIcon(source, getId(), dimension, IconType.disable); - } - - /** - * 创建一份白化图标 - * - * @return 白化图标 - */ - @NotNull - @Override - public Icon white() { - return new PluginLazyIcon(source, getId(), dimension, IconType.white); - } - - - @Override - public String toString() { - return new StringJoiner(", ", PluginLazyIcon.class.getSimpleName() + "[", "]") - .add("source='" + source + "'") - .add("id='" + id + "'") - .add("size=" + "[w=" + scale(dimension.width) + ",h=" + scale(dimension.height) + "]") - .add("type=" + type) - .toString(); - } -} diff --git a/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginListIconSet.java b/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginListIconSet.java new file mode 100644 index 0000000000..4034ef01ef --- /dev/null +++ b/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginListIconSet.java @@ -0,0 +1,57 @@ +package com.fine.theme.icon.plugin; + +import com.fine.theme.icon.AbstractIconSet; +import com.fine.theme.icon.IconManager; +import com.fine.theme.icon.img.ImageIconSource; +import com.fine.theme.icon.svg.SvgIconSource; + +import java.util.List; +import java.util.Objects; + +/** + * 插件 map 图标集 + * 为了保证 插件之间,插件与设计器 icon id 的唯一性,以图标 path 为 id 进行注册 + * + * @author lemon + * @since + * Created on 2024/08/20 + */ +public class PluginListIconSet extends AbstractIconSet { + + public PluginListIconSet(String id, List icons) { + this.name = id; + addIconWithList(icons); + } + + + /** + * 根据 list 注册图标 + * @param icons icon path list + */ + public void addIconWithList(List icons) { + for (String path : icons) { + if (IconManager.isSvgIcon(path)) { + addIcon(new SvgIconSource(path, path)); + } else if (IconManager.isImageIcon(path)) { + addIcon(new ImageIconSource(path, path)); + } + } + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PluginListIconSet that = (PluginListIconSet) o; + return Objects.equals(name, that.name); + } + + @Override + public int hashCode() { + return Objects.hashCode(name); + } +} diff --git a/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginMapIconSet.java b/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginMapIconSet.java deleted file mode 100644 index fdc32bac63..0000000000 --- a/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginMapIconSet.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.fine.theme.icon.plugin; - -import com.fine.theme.icon.AbstractIconSet; -import com.fine.theme.icon.img.ImageIconSource; -import com.fine.theme.icon.svg.SvgIconSource; - -import java.util.Map; -import java.util.Objects; - -/** - * 插件 map 图标集 - * - * @author lemon - * @since - * Created on 2024/08/20 - */ -public class PluginMapIconSet extends AbstractIconSet { - - public PluginMapIconSet(Map iconId2Path) { - addIconWithMap(iconId2Path); - } - - - /** - * 根据 map 注册图标 - * @param iconId2Path key: id, value: icon path - */ - public void addIconWithMap(Map iconId2Path) { - for (Map.Entry entry: iconId2Path.entrySet()) { - if (PluginIconManager.isSvgIcon(entry.getValue())) { - addIcon(new SvgIconSource(entry.getKey(), entry.getValue())); - } else if (PluginIconManager.isImageIcon(entry.getValue())) { - addIcon(new ImageIconSource(entry.getKey(), entry.getValue())); - } - } - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - PluginMapIconSet that = (PluginMapIconSet) o; - return Objects.equals(name, that.name); - } - - @Override - public int hashCode() { - return Objects.hashCode(name); - } -} diff --git a/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineDarkLaf.java b/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineDarkLaf.java index f06d8ee888..df1c597d46 100644 --- a/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineDarkLaf.java +++ b/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineDarkLaf.java @@ -4,7 +4,6 @@ import com.fine.swing.ui.layout.Layouts; import com.fine.theme.icon.IconManager; import com.fine.theme.light.ui.FineLightIconSet; import com.formdev.flatlaf.util.UIScale; -import com.fr.design.fun.LazyIconProvider; import com.fr.stable.StringUtils; /** @@ -27,14 +26,14 @@ public class FineDarkLaf extends FineLaf { */ public static boolean setup() { IconManager.addSet(new FineLightIconSet()); - // dark_icon 目前还没适配,先使用 light_icon - insertIconProvider(LazyIconProvider.THEME.LIGHT_ICON); Layouts.setScaleFactor(UIScale.getUserScaleFactor()); UIScale.addPropertyChangeListener(evt -> { if (StringUtils.equals(evt.getPropertyName(), USER_SCALE_FACTOR)) { Layouts.setScaleFactor((float) evt.getNewValue()); } }); + // dark_icon 目前还没适配,先使用 light_icon + listenPluginIcons(false); return setup(new FineDarkLaf()); } diff --git a/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLaf.java b/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLaf.java index f28f1e11d0..a005aa1c4c 100644 --- a/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLaf.java +++ b/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLaf.java @@ -1,16 +1,15 @@ package com.fine.theme.light.ui.laf; +import com.fine.theme.icon.IconManager; import com.fine.theme.icon.IconSet; import com.fine.theme.icon.UrlIconResource; -import com.fine.theme.icon.plugin.PluginIconManager; import com.fine.theme.icon.plugin.PluginJsonIconSet; -import com.fine.theme.icon.plugin.PluginMapIconSet; +import com.fine.theme.icon.plugin.PluginListIconSet; import com.formdev.flatlaf.FlatLaf; import com.formdev.flatlaf.util.SystemInfo; -import com.fr.design.ExtraDesignClassManager; import com.fr.design.fun.LazyIconProvider; -import com.fr.general.ComparatorUtils; import com.fr.general.GeneralContext; +import com.fr.nx.app.web.out.widget.utils.CollectionUtils; import com.fr.plugin.manage.PluginFilter; import com.fr.plugin.observer.PluginEvent; import com.fr.plugin.observer.PluginEventListener; @@ -35,27 +34,36 @@ public abstract class FineLaf extends FlatLaf { private static final String NAME = "FineLaf"; - private static void handlePluginEvent(PluginEvent event, LazyIconProvider.THEME category, + private static void handlePluginEvent(PluginEvent event, boolean isDark, BiConsumer> operation) { Set set = event.getContext().getRuntime().get(LazyIconProvider.MARK_STRING); - dealWithPluginIcon(set, category, operation); + dealWithPluginIcon(set, isDark, operation); } - private static void dealWithPluginIcon(Set set, LazyIconProvider.THEME category, + private static void dealWithPluginIcon(Set set, boolean isDark, BiConsumer> operation) { for (LazyIconProvider provider : set) { - if (!ComparatorUtils.equals(provider.themeCategory(), category)) { + if (provider.isDark() != isDark) { continue; } - List iconSets = new ArrayList<>(); - PluginJsonIconSet jsonIconSet = new PluginJsonIconSet(new UrlIconResource(provider.jsonPath())); - iconSets.add(jsonIconSet); - PluginMapIconSet mapIconSet = new PluginMapIconSet(provider.iconId2Path()); - iconSets.add(mapIconSet); + List iconSets = generatePluginIconSet(provider); operation.accept(provider, iconSets); } } + private static List generatePluginIconSet(LazyIconProvider provider) { + List iconSets = new ArrayList<>(); + if (provider.jsonPath() != null) { + PluginJsonIconSet jsonIconSet = new PluginJsonIconSet(provider.id(), new UrlIconResource(provider.jsonPath())); + iconSets.add(jsonIconSet); + } + if (CollectionUtils.isNotEmpty(provider.icons())) { + PluginListIconSet listIconSet = new PluginListIconSet(provider.id(), provider.icons()); + iconSets.add(listIconSet); + } + return iconSets; + } + @Override public String getName() { return NAME; @@ -93,43 +101,28 @@ public abstract class FineLaf extends FlatLaf { /** * 适配插件图标 Icon - * @param category 图标 Icon 分类 {@link LazyIconProvider.THEME} + * @param isDark 图标 Icon 主题,light 或者 dark */ - public static void insertIconProvider(LazyIconProvider.THEME category) { - Set set = ExtraDesignClassManager.getInstance().getArray(LazyIconProvider.MARK_STRING); - dealWithPluginIcon(set, category, (provider, iconSets) -> PluginIconManager.addSet(provider.pluginId(), iconSets)); - listenerPlugins(category); - } - - private static void listenerPlugins(LazyIconProvider.THEME category) { + public static void listenPluginIcons(boolean isDark) { //注册插件监听 PluginFilter filter = context -> context.contain(LazyIconProvider.MARK_STRING); PluginEventListener insert = new PluginEventListener() { @Override public void on(PluginEvent event) { - handlePluginEvent(event, category, (provider, iconSets) -> PluginIconManager.addSet(provider.pluginId(), iconSets)); - } - }; - - PluginEventListener update = new PluginEventListener() { - @Override - public void on(PluginEvent event) { - handlePluginEvent(event, category, (provider, iconSets) -> PluginIconManager.updateSet(provider.pluginId(), iconSets)); + handlePluginEvent(event, isDark, (provider, iconSets) -> IconManager.addSet(iconSets)); } }; PluginEventListener remove = new PluginEventListener() { @Override public void on(PluginEvent event) { - handlePluginEvent(event, category, (provider, iconSets) -> PluginIconManager.removeSet(provider.pluginId())); + handlePluginEvent(event, isDark, (provider, iconSets) -> IconManager.removeSet(provider.id())); } }; GeneralContext.listenPlugin(PluginEventType.AfterRun, insert, filter); GeneralContext.listenPlugin(PluginEventType.AfterInstall, insert, filter); - GeneralContext.listenPlugin(PluginEventType.AfterUpdate, update, filter); - GeneralContext.listenPlugin(PluginEventType.AfterActive, update, filter); GeneralContext.listenPlugin(PluginEventType.AfterForbid, remove, filter); GeneralContext.listenPlugin(PluginEventType.AfterUninstall, remove, filter); } diff --git a/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLightLaf.java b/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLightLaf.java index 08a0602d62..5acb9a7a04 100644 --- a/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLightLaf.java +++ b/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLightLaf.java @@ -4,7 +4,6 @@ import com.fine.swing.ui.layout.Layouts; import com.fine.theme.icon.IconManager; import com.fine.theme.light.ui.FineLightIconSet; import com.formdev.flatlaf.util.UIScale; -import com.fr.design.fun.LazyIconProvider; import com.fr.stable.StringUtils; /** @@ -27,13 +26,13 @@ public class FineLightLaf extends FineLaf { */ public static boolean setup() { IconManager.addSet(new FineLightIconSet()); - insertIconProvider(LazyIconProvider.THEME.LIGHT_ICON); Layouts.setScaleFactor(UIScale.getUserScaleFactor()); UIScale.addPropertyChangeListener(evt -> { if (StringUtils.equals(evt.getPropertyName(), USER_SCALE_FACTOR)) { Layouts.setScaleFactor((float) evt.getNewValue()); } }); + listenPluginIcons(false); return setup(new FineLightLaf()); } diff --git a/designer-base/src/main/java/com/fr/design/fun/LazyIconProvider.java b/designer-base/src/main/java/com/fr/design/fun/LazyIconProvider.java index 1a9fc8095d..edde0535e6 100644 --- a/designer-base/src/main/java/com/fr/design/fun/LazyIconProvider.java +++ b/designer-base/src/main/java/com/fr/design/fun/LazyIconProvider.java @@ -2,7 +2,7 @@ package com.fr.design.fun; import com.fr.stable.fun.mark.Mutable; -import java.util.Map; +import java.util.List; /** * 插件图标适配接口 @@ -13,6 +13,8 @@ import java.util.Map; */ public interface LazyIconProvider extends Mutable { String MARK_STRING = "LazyIconProvider"; + String DARK_SUFFIX = "_dark"; + String LIGHT_SUFFIX = "_light"; int CURRENT_LEVEL = 1; @@ -30,39 +32,25 @@ public interface LazyIconProvider extends Mutable { */ String jsonPath(); - /** - * 图标所属主题分类 - * - * @return 主题类别 - */ - THEME themeCategory(); - /** * 构建需要注册的图标 key: id, value: icon path * @return map */ - Map iconId2Path(); + List icons(); /** - * 图标主题 + * 主题类别 light, dark + * @return 是否是 dark */ - enum THEME { - - /** - * light_icon - */ - LIGHT_ICON("light_icon"), + boolean isDark(); - /** - * dark_icon - */ - DARK_ICON("dark_icon") - ; - - final String category; - THEME(String category) { - this.category = category; - } + /** + * 插件注册的 iconSet id 根据主题设置为 pluginId_light 或者 pluginId_dark + * 同种主题内部的 iconSet id 不做区分 + * @return iconSet id + */ + default String id() { + String suffix = isDark() ? DARK_SUFFIX : LIGHT_SUFFIX; + return pluginId() + suffix; } - } diff --git a/designer-base/src/main/java/com/fr/design/fun/impl/AbstractLazyIconProvider.java b/designer-base/src/main/java/com/fr/design/fun/impl/AbstractLazyIconProvider.java index 6da1316497..187b9deecd 100644 --- a/designer-base/src/main/java/com/fr/design/fun/impl/AbstractLazyIconProvider.java +++ b/designer-base/src/main/java/com/fr/design/fun/impl/AbstractLazyIconProvider.java @@ -4,9 +4,7 @@ import com.fr.design.fun.LazyIconProvider; import com.fr.stable.fun.impl.AbstractProvider; import com.fr.stable.fun.mark.API; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.util.Map; +import java.util.List; /** @@ -49,23 +47,18 @@ public class AbstractLazyIconProvider extends AbstractProvider implements LazyIc } /** - * 图标主题 {@link THEME} + * 直接注册图标:元素是 icon path * - * @return 主题类别 + * @return list */ @Override - public THEME themeCategory() { + public List icons() { return null; } - /** - * 直接注册图标:key 是 icon id, value 是 icon path - * - * @return map - */ @Override - public Map iconId2Path() { - return null; + public boolean isDark() { + return false; } } From 0bb4343b654ebfa79702fea161139bba49293ae4 Mon Sep 17 00:00:00 2001 From: "Destiny.Lin" Date: Wed, 4 Sep 2024 19:02:59 +0800 Subject: [PATCH 08/10] =?UTF-8?q?=E6=97=A0jira=E4=BB=BB=E5=8A=A1=EF=BC=8C?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=89=93=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/fanruan/boot/pre/DesignPreStartComponent.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/designer-realize/src/main/java/com/fanruan/boot/pre/DesignPreStartComponent.java b/designer-realize/src/main/java/com/fanruan/boot/pre/DesignPreStartComponent.java index eca6315272..06459b8fe3 100644 --- a/designer-realize/src/main/java/com/fanruan/boot/pre/DesignPreStartComponent.java +++ b/designer-realize/src/main/java/com/fanruan/boot/pre/DesignPreStartComponent.java @@ -61,7 +61,7 @@ import com.fr.tenant.config.TenantConfigProvider; import com.fr.tenant.context.CurrentTenantProviderStater; import com.fr.tenant.context.TenantContext; import com.fr.tenant.context.provider.CurrentTenantKey; -import com.fr.tenant.store.impl.DefaultTenantStorage; +import com.fr.tenant.store.impl.MemoryTenantStorage; import com.fr.workspace.WorkContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -208,7 +208,7 @@ public class DesignPreStartComponent { private void startTenant() { - TenantContext.registerStorage(new DefaultTenantStorage()); + TenantContext.registerStorage(new MemoryTenantStorage()); TenantContext.registerConfigProvider(new TenantConfigProvider() { @Override public boolean isMultiTenantOpen() { From 9513c664c4be44cee200967fb9acc9230d88fa54 Mon Sep 17 00:00:00 2001 From: lemon Date: Fri, 6 Sep 2024 15:57:08 +0800 Subject: [PATCH 09/10] =?UTF-8?q?REPORT-127437=20fix:=20=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E5=9B=BE=E6=A0=87=E9=80=82=E9=85=8D=E4=BB=A3=E7=A0=81=E8=B0=83?= =?UTF-8?q?=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/fine/theme/icon/IconManager.java | 55 +++++++- .../fine/theme/icon/plugin/PluginIconSet.java | 127 ++++++++++++++++++ .../theme/icon/plugin/PluginJsonIconSet.java | 22 --- .../theme/icon/plugin/PluginListIconSet.java | 57 -------- .../fine/theme/light/ui/laf/FineDarkLaf.java | 5 +- .../com/fine/theme/light/ui/laf/FineLaf.java | 74 ---------- .../fine/theme/light/ui/laf/FineLightLaf.java | 4 +- .../com/fr/design/fun/LazyIconProvider.java | 31 +---- .../fun/impl/AbstractLazyIconProvider.java | 21 ++- .../mainframe/toolbar/LookAndFeelAction.java | 3 + 10 files changed, 195 insertions(+), 204 deletions(-) create mode 100644 designer-base/src/main/java/com/fine/theme/icon/plugin/PluginIconSet.java delete mode 100644 designer-base/src/main/java/com/fine/theme/icon/plugin/PluginJsonIconSet.java delete mode 100644 designer-base/src/main/java/com/fine/theme/icon/plugin/PluginListIconSet.java diff --git a/designer-base/src/main/java/com/fine/theme/icon/IconManager.java b/designer-base/src/main/java/com/fine/theme/icon/IconManager.java index 86506c8475..48f7660b2b 100644 --- a/designer-base/src/main/java/com/fine/theme/icon/IconManager.java +++ b/designer-base/src/main/java/com/fine/theme/icon/IconManager.java @@ -1,5 +1,8 @@ package com.fine.theme.icon; +import com.fine.theme.icon.plugin.PluginIconSet; +import com.fine.theme.light.ui.FineLightIconSet; +import com.formdev.flatlaf.FlatLaf; import com.fr.base.extension.FileExtension; import com.fr.general.IOUtils; import com.fr.log.FineLoggerFactory; @@ -9,12 +12,13 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.Icon; +import javax.swing.LookAndFeel; +import javax.swing.UIManager; import java.awt.Dimension; import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArrayList; /** * 图标管理器 @@ -29,11 +33,41 @@ import java.util.concurrent.CopyOnWriteArrayList; */ @Immutable public class IconManager { - public static final String ICON_DISABLE_SUFFIX = "_disable"; public static final Dimension DEFAULT_DIMENSION = new Dimension(16, 16); - private static final CopyOnWriteArrayList ICON_SETS = new CopyOnWriteArrayList<>(); - private static final Map> CACHE = new ConcurrentHashMap<>(64); + private static final ArrayList ICON_SETS = new ArrayList<>(); + private static final HashMap> CACHE = new HashMap<>(64); + + /** + * 初始化 Icon:FineIcon、PluginIcon + */ + public static void initializeIcon() { + addIconSet(); + } + + /** + * 切换 Icon + */ + public static void updateIcon() { + ICON_SETS.clear(); + clearCache(); + addIconSet(); + } + + private static void addIconSet() { + boolean dark = false; + LookAndFeel laf = UIManager.getLookAndFeel(); + if (laf instanceof FlatLaf) { + dark = ((FlatLaf) laf).isDark(); + } + if (dark) { + // dark 主题还没适配 + addSet(new FineLightIconSet()); + } else { + addSet(new FineLightIconSet()); + } + addSet(new PluginIconSet()); + } /** @@ -43,10 +77,17 @@ public class IconManager { * @return 图标集 */ public static IconSet getSet(String id) { + IconSet iconSet = null; for (IconSet set : ICON_SETS) { if (set.getId().equals(id)) { - return set; + iconSet = set; } + if (set instanceof PluginIconSet && iconSet == null) { + iconSet = PluginIconSet.getIconSet(id); + } + } + if (iconSet != null) { + return iconSet; } throw new IconException("[IconManager] Can not find icon set by id: " + id); } diff --git a/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginIconSet.java b/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginIconSet.java new file mode 100644 index 0000000000..39d8c04112 --- /dev/null +++ b/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginIconSet.java @@ -0,0 +1,127 @@ +package com.fine.theme.icon.plugin; + +import com.fine.theme.icon.AbstractIconSet; +import com.fine.theme.icon.IconSet; +import com.fine.theme.icon.IconType; +import com.fine.theme.icon.JsonIconSet; +import com.fine.theme.icon.UrlIconResource; +import com.formdev.flatlaf.FlatLaf; +import com.fr.design.fun.LazyIconProvider; +import com.fr.general.GeneralContext; +import com.fr.plugin.manage.PluginFilter; +import com.fr.plugin.observer.PluginEvent; +import com.fr.plugin.observer.PluginEventListener; +import com.fr.plugin.observer.PluginEventType; +import com.fr.stable.AssistUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.Icon; +import javax.swing.LookAndFeel; +import javax.swing.UIManager; +import java.awt.Dimension; +import java.util.ArrayList; +import java.util.Set; +import java.util.function.Consumer; + + +/** + * 管理插件 iconSet + * @author lemon + * @since + * Created on + */ +public class PluginIconSet extends AbstractIconSet { + + private static final String NAME = "Plugin Icon Set"; + private static final ArrayList PLUGIN_ICON_SETS = new ArrayList<>(); + + public PluginIconSet() { + name = NAME; + listenPluginIcons(); + } + + /** + * 适配插件图标 Icon + */ + public static void listenPluginIcons() { + //注册插件监听 + PluginFilter filter = context -> context.contain(LazyIconProvider.MARK_STRING); + + PluginEventListener insert = new PluginEventListener() { + @Override + public void on(PluginEvent event) { + handlePluginEvent(event, (provider) -> PLUGIN_ICON_SETS.add(generateJsonIconSet(provider))); + } + }; + + PluginEventListener remove = new PluginEventListener() { + @Override + public void on(PluginEvent event) { + handlePluginEvent(event, (provider) -> PLUGIN_ICON_SETS.removeIf(iconSet -> iconSet.getId().equals(provider.pluginId()))); + } + }; + + GeneralContext.listenPlugin(PluginEventType.AfterRun, insert, filter); + GeneralContext.listenPlugin(PluginEventType.AfterInstall, insert, filter); + GeneralContext.listenPlugin(PluginEventType.AfterForbid, remove, filter); + GeneralContext.listenPlugin(PluginEventType.AfterUninstall, remove, filter); + } + + private static void handlePluginEvent(PluginEvent event, Consumer consumer) { + Set set = event.getContext().getRuntime().get(LazyIconProvider.MARK_STRING); + for (LazyIconProvider provider : set) { + consumer.accept(provider); + } + } + + private static JsonIconSet generateJsonIconSet(LazyIconProvider provider) { + LookAndFeel laf = UIManager.getLookAndFeel(); + boolean dark = ((FlatLaf) laf).isDark(); + String jsonPath = dark ? provider.darkJsonPath() : provider.lightJsonPath(); + return new JsonIconSet(new UrlIconResource(jsonPath)) { + @Override + public @NotNull String getId() { + return provider.pluginId(); + } + }; + } + + @Override + public @Nullable Icon findIcon(@NotNull String id, @NotNull Dimension dimension, IconType type) { + Icon icon; + for (IconSet iconSet : PLUGIN_ICON_SETS) { + icon = iconSet.findIcon(id, dimension, type); + if (icon != null) { + return icon; + } + } + return null; + } + + /** + * 根据 id 匹配 icon set + * @param id 对于 plugin icon set, id 是 plugin_id + * @return icon set + */ + public static IconSet getIconSet(@NotNull final String id ) { + for (IconSet iconSet : PLUGIN_ICON_SETS) { + if (iconSet.getId().equals(id)) { + return iconSet; + } + } + return null; + } + + + @Override + public boolean equals(Object obj) { + return obj instanceof PluginIconSet + && AssistUtils.equals(this.name, ((PluginIconSet) obj).name); + } + + @Override + public int hashCode() { + return AssistUtils.hashCode(name); + } +} diff --git a/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginJsonIconSet.java b/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginJsonIconSet.java deleted file mode 100644 index 75a12c6a43..0000000000 --- a/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginJsonIconSet.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.fine.theme.icon.plugin; - -import com.fine.theme.icon.JsonIconSet; -import com.fine.theme.icon.UrlIconResource; - -/** - * 插件 json 图标集 - * json 格式参考 fine_light.icon.json - * 为了保证 插件之间,插件与设计器 icon id 的唯一性,icons key 值规则参考 {@link PluginListIconSet} - * - * @author lemon - * @since - * Created on 2024/08/20 - */ -public class PluginJsonIconSet extends JsonIconSet { - - public PluginJsonIconSet(String id, UrlIconResource resource) { - super(resource); - this.name = id; - } - -} diff --git a/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginListIconSet.java b/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginListIconSet.java deleted file mode 100644 index 4034ef01ef..0000000000 --- a/designer-base/src/main/java/com/fine/theme/icon/plugin/PluginListIconSet.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.fine.theme.icon.plugin; - -import com.fine.theme.icon.AbstractIconSet; -import com.fine.theme.icon.IconManager; -import com.fine.theme.icon.img.ImageIconSource; -import com.fine.theme.icon.svg.SvgIconSource; - -import java.util.List; -import java.util.Objects; - -/** - * 插件 map 图标集 - * 为了保证 插件之间,插件与设计器 icon id 的唯一性,以图标 path 为 id 进行注册 - * - * @author lemon - * @since - * Created on 2024/08/20 - */ -public class PluginListIconSet extends AbstractIconSet { - - public PluginListIconSet(String id, List icons) { - this.name = id; - addIconWithList(icons); - } - - - /** - * 根据 list 注册图标 - * @param icons icon path list - */ - public void addIconWithList(List icons) { - for (String path : icons) { - if (IconManager.isSvgIcon(path)) { - addIcon(new SvgIconSource(path, path)); - } else if (IconManager.isImageIcon(path)) { - addIcon(new ImageIconSource(path, path)); - } - } - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - PluginListIconSet that = (PluginListIconSet) o; - return Objects.equals(name, that.name); - } - - @Override - public int hashCode() { - return Objects.hashCode(name); - } -} diff --git a/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineDarkLaf.java b/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineDarkLaf.java index df1c597d46..0af36de488 100644 --- a/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineDarkLaf.java +++ b/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineDarkLaf.java @@ -2,7 +2,6 @@ package com.fine.theme.light.ui.laf; import com.fine.swing.ui.layout.Layouts; import com.fine.theme.icon.IconManager; -import com.fine.theme.light.ui.FineLightIconSet; import com.formdev.flatlaf.util.UIScale; import com.fr.stable.StringUtils; @@ -25,15 +24,13 @@ public class FineDarkLaf extends FineLaf { * @return 是否安装成功 */ public static boolean setup() { - IconManager.addSet(new FineLightIconSet()); + IconManager.initializeIcon(); Layouts.setScaleFactor(UIScale.getUserScaleFactor()); UIScale.addPropertyChangeListener(evt -> { if (StringUtils.equals(evt.getPropertyName(), USER_SCALE_FACTOR)) { Layouts.setScaleFactor((float) evt.getNewValue()); } }); - // dark_icon 目前还没适配,先使用 light_icon - listenPluginIcons(false); return setup(new FineDarkLaf()); } diff --git a/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLaf.java b/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLaf.java index a005aa1c4c..aa67a7d2ca 100644 --- a/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLaf.java +++ b/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLaf.java @@ -1,25 +1,9 @@ package com.fine.theme.light.ui.laf; -import com.fine.theme.icon.IconManager; -import com.fine.theme.icon.IconSet; -import com.fine.theme.icon.UrlIconResource; -import com.fine.theme.icon.plugin.PluginJsonIconSet; -import com.fine.theme.icon.plugin.PluginListIconSet; import com.formdev.flatlaf.FlatLaf; import com.formdev.flatlaf.util.SystemInfo; -import com.fr.design.fun.LazyIconProvider; -import com.fr.general.GeneralContext; -import com.fr.nx.app.web.out.widget.utils.CollectionUtils; -import com.fr.plugin.manage.PluginFilter; -import com.fr.plugin.observer.PluginEvent; -import com.fr.plugin.observer.PluginEventListener; -import com.fr.plugin.observer.PluginEventType; import javax.swing.PopupFactory; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.function.BiConsumer; /** * Fine designer new look and feel @@ -34,36 +18,6 @@ public abstract class FineLaf extends FlatLaf { private static final String NAME = "FineLaf"; - private static void handlePluginEvent(PluginEvent event, boolean isDark, - BiConsumer> operation) { - Set set = event.getContext().getRuntime().get(LazyIconProvider.MARK_STRING); - dealWithPluginIcon(set, isDark, operation); - } - - private static void dealWithPluginIcon(Set set, boolean isDark, - BiConsumer> operation) { - for (LazyIconProvider provider : set) { - if (provider.isDark() != isDark) { - continue; - } - List iconSets = generatePluginIconSet(provider); - operation.accept(provider, iconSets); - } - } - - private static List generatePluginIconSet(LazyIconProvider provider) { - List iconSets = new ArrayList<>(); - if (provider.jsonPath() != null) { - PluginJsonIconSet jsonIconSet = new PluginJsonIconSet(provider.id(), new UrlIconResource(provider.jsonPath())); - iconSets.add(jsonIconSet); - } - if (CollectionUtils.isNotEmpty(provider.icons())) { - PluginListIconSet listIconSet = new PluginListIconSet(provider.id(), provider.icons()); - iconSets.add(listIconSet); - } - return iconSets; - } - @Override public String getName() { return NAME; @@ -99,32 +53,4 @@ public abstract class FineLaf extends FlatLaf { } } - /** - * 适配插件图标 Icon - * @param isDark 图标 Icon 主题,light 或者 dark - */ - public static void listenPluginIcons(boolean isDark) { - //注册插件监听 - PluginFilter filter = context -> context.contain(LazyIconProvider.MARK_STRING); - - PluginEventListener insert = new PluginEventListener() { - @Override - public void on(PluginEvent event) { - handlePluginEvent(event, isDark, (provider, iconSets) -> IconManager.addSet(iconSets)); - } - }; - - PluginEventListener remove = new PluginEventListener() { - @Override - public void on(PluginEvent event) { - handlePluginEvent(event, isDark, (provider, iconSets) -> IconManager.removeSet(provider.id())); - } - }; - - GeneralContext.listenPlugin(PluginEventType.AfterRun, insert, filter); - GeneralContext.listenPlugin(PluginEventType.AfterInstall, insert, filter); - GeneralContext.listenPlugin(PluginEventType.AfterForbid, remove, filter); - GeneralContext.listenPlugin(PluginEventType.AfterUninstall, remove, filter); - } - } diff --git a/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLightLaf.java b/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLightLaf.java index 5acb9a7a04..5ccc51a8b1 100644 --- a/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLightLaf.java +++ b/designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLightLaf.java @@ -2,7 +2,6 @@ package com.fine.theme.light.ui.laf; import com.fine.swing.ui.layout.Layouts; import com.fine.theme.icon.IconManager; -import com.fine.theme.light.ui.FineLightIconSet; import com.formdev.flatlaf.util.UIScale; import com.fr.stable.StringUtils; @@ -25,14 +24,13 @@ public class FineLightLaf extends FineLaf { * @return 是否安装成功 */ public static boolean setup() { - IconManager.addSet(new FineLightIconSet()); + IconManager.initializeIcon(); Layouts.setScaleFactor(UIScale.getUserScaleFactor()); UIScale.addPropertyChangeListener(evt -> { if (StringUtils.equals(evt.getPropertyName(), USER_SCALE_FACTOR)) { Layouts.setScaleFactor((float) evt.getNewValue()); } }); - listenPluginIcons(false); return setup(new FineLightLaf()); } diff --git a/designer-base/src/main/java/com/fr/design/fun/LazyIconProvider.java b/designer-base/src/main/java/com/fr/design/fun/LazyIconProvider.java index edde0535e6..f51a2323d7 100644 --- a/designer-base/src/main/java/com/fr/design/fun/LazyIconProvider.java +++ b/designer-base/src/main/java/com/fr/design/fun/LazyIconProvider.java @@ -2,8 +2,6 @@ package com.fr.design.fun; import com.fr.stable.fun.mark.Mutable; -import java.util.List; - /** * 插件图标适配接口 * @@ -13,8 +11,6 @@ import java.util.List; */ public interface LazyIconProvider extends Mutable { String MARK_STRING = "LazyIconProvider"; - String DARK_SUFFIX = "_dark"; - String LIGHT_SUFFIX = "_light"; int CURRENT_LEVEL = 1; @@ -25,32 +21,19 @@ public interface LazyIconProvider extends Mutable { */ String pluginId(); + /** - * json 文件路径 + * light 主题 * * @return 图标注册 json 路径 */ - String jsonPath(); - - /** - * 构建需要注册的图标 key: id, value: icon path - * @return map - */ - List icons(); + String lightJsonPath(); /** - * 主题类别 light, dark - * @return 是否是 dark + * dark 主题 + * + * @return 图标注册 json 路径 */ - boolean isDark(); + String darkJsonPath(); - /** - * 插件注册的 iconSet id 根据主题设置为 pluginId_light 或者 pluginId_dark - * 同种主题内部的 iconSet id 不做区分 - * @return iconSet id - */ - default String id() { - String suffix = isDark() ? DARK_SUFFIX : LIGHT_SUFFIX; - return pluginId() + suffix; - } } diff --git a/designer-base/src/main/java/com/fr/design/fun/impl/AbstractLazyIconProvider.java b/designer-base/src/main/java/com/fr/design/fun/impl/AbstractLazyIconProvider.java index 187b9deecd..916a100923 100644 --- a/designer-base/src/main/java/com/fr/design/fun/impl/AbstractLazyIconProvider.java +++ b/designer-base/src/main/java/com/fr/design/fun/impl/AbstractLazyIconProvider.java @@ -15,7 +15,7 @@ import java.util.List; * Created on */ @API(level = LazyIconProvider.CURRENT_LEVEL) -public class AbstractLazyIconProvider extends AbstractProvider implements LazyIconProvider { +public abstract class AbstractLazyIconProvider extends AbstractProvider implements LazyIconProvider { /** * 当前接口的API等级,用于判断是否需要升级插件 @@ -37,28 +37,23 @@ public class AbstractLazyIconProvider extends AbstractProvider implements LazyIc } /** - * 通过 json 注册图标 + * light 主题 * * @return 图标注册 json 路径 */ @Override - public String jsonPath() { - return null; + public String lightJsonPath() { + return ""; } /** - * 直接注册图标:元素是 icon path + * dark 主题 * - * @return list + * @return 图标注册 json 路径 */ @Override - public List icons() { - return null; - } - - @Override - public boolean isDark() { - return false; + public String darkJsonPath() { + return ""; } } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/toolbar/LookAndFeelAction.java b/designer-base/src/main/java/com/fr/design/mainframe/toolbar/LookAndFeelAction.java index 613fe0a0c1..3edf09d953 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/toolbar/LookAndFeelAction.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/toolbar/LookAndFeelAction.java @@ -5,6 +5,7 @@ package com.fr.design.mainframe.toolbar; +import com.fine.theme.icon.IconManager; import com.formdev.flatlaf.FlatLaf; import com.formdev.flatlaf.extras.FlatAnimatedLafChange; import com.fr.design.actions.UpdateAction; @@ -32,6 +33,8 @@ public class LookAndFeelAction extends UpdateAction { FlatAnimatedLafChange.showSnapshot(); try { UIManager.setLookAndFeel( lookAndFeel ); + // 多主题场景下,需要判断是否需要切换图标 + IconManager.updateIcon(); } catch (UnsupportedLookAndFeelException e) { throw new RuntimeException(e); } From 5c244766431942a105d58f8ea0e1e0e4eba8ebe6 Mon Sep 17 00:00:00 2001 From: lemon Date: Fri, 6 Sep 2024 16:00:27 +0800 Subject: [PATCH 10/10] =?UTF-8?q?REPORT-127437=20fix:=20=E5=8E=BB=E6=8E=89?= =?UTF-8?q?=E4=B8=8D=E7=94=A8=E7=9A=84=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/fine/theme/icon/IconManager.java | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/designer-base/src/main/java/com/fine/theme/icon/IconManager.java b/designer-base/src/main/java/com/fine/theme/icon/IconManager.java index 48f7660b2b..01f722e24b 100644 --- a/designer-base/src/main/java/com/fine/theme/icon/IconManager.java +++ b/designer-base/src/main/java/com/fine/theme/icon/IconManager.java @@ -6,7 +6,6 @@ import com.formdev.flatlaf.FlatLaf; import com.fr.base.extension.FileExtension; import com.fr.general.IOUtils; import com.fr.log.FineLoggerFactory; -import com.fr.nx.app.web.out.widget.utils.CollectionUtils; import com.fr.third.errorprone.annotations.Immutable; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -167,28 +166,6 @@ public class IconManager { return id + "_" + dimension.width + "_" + dimension.height + "_" + type; } - /** - * 批量添加图标集 - * - * @param sets 图标集 - */ - public static void addSet(@NotNull List sets) { - if (CollectionUtils.isEmpty(sets)) { - return; - } - sets.forEach(IconManager::addSet); - } - - /** - * 删除指定 id 图标集 - * - * @param id 图标集ID - */ - public static void removeSet(@NotNull String id) { - ICON_SETS.removeIf(iconSet -> id.equals(iconSet.getId())); - clearCache(); - } - /** * 是否SVG图标格式 *