From 9513c664c4be44cee200967fb9acc9230d88fa54 Mon Sep 17 00:00:00 2001 From: lemon Date: Fri, 6 Sep 2024 15:57:08 +0800 Subject: [PATCH] =?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); }