Browse Source

REPORT-127437 fix: 调整代码逻辑,插件跟设计器共用 icon 加载方式,调整插件 icon 和 set 的 id 标识

fbp/feature
lemon 3 months ago
parent
commit
91d3d558fb
  1. 33
      designer-base/src/main/java/com/fine/theme/icon/IconManager.java
  2. 223
      designer-base/src/main/java/com/fine/theme/icon/plugin/PluginIconManager.java
  3. 113
      designer-base/src/main/java/com/fine/theme/icon/plugin/PluginJsonIconSet.java
  4. 137
      designer-base/src/main/java/com/fine/theme/icon/plugin/PluginLazyIcon.java
  5. 57
      designer-base/src/main/java/com/fine/theme/icon/plugin/PluginListIconSet.java
  6. 54
      designer-base/src/main/java/com/fine/theme/icon/plugin/PluginMapIconSet.java
  7. 5
      designer-base/src/main/java/com/fine/theme/light/ui/laf/FineDarkLaf.java
  8. 55
      designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLaf.java
  9. 3
      designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLightLaf.java
  10. 38
      designer-base/src/main/java/com/fr/design/fun/LazyIconProvider.java
  11. 19
      designer-base/src/main/java/com/fr/design/fun/impl/AbstractLazyIconProvider.java

33
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.base.extension.FileExtension;
import com.fr.general.IOUtils; import com.fr.general.IOUtils;
import com.fr.log.FineLoggerFactory; import com.fr.log.FineLoggerFactory;
import com.fr.nx.app.web.out.widget.utils.CollectionUtils;
import com.fr.third.errorprone.annotations.Immutable; import com.fr.third.errorprone.annotations.Immutable;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -10,8 +11,10 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.Icon; import javax.swing.Icon;
import java.awt.Dimension; import java.awt.Dimension;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.ArrayList; import java.util.List;
import java.util.HashMap; 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 String ICON_DISABLE_SUFFIX = "_disable";
public static final Dimension DEFAULT_DIMENSION = new Dimension(16, 16); public static final Dimension DEFAULT_DIMENSION = new Dimension(16, 16);
private static final ArrayList<IconSet> ICON_SETS = new ArrayList<>(2); private static final CopyOnWriteArrayList<IconSet> ICON_SETS = new CopyOnWriteArrayList<>();
private static final HashMap<String, WeakReference<Icon>> CACHE = new HashMap<>(64); private static final Map<String, WeakReference<Icon>> CACHE = new ConcurrentHashMap<>(64);
/** /**
@ -123,6 +126,28 @@ public class IconManager {
return id + "_" + dimension.width + "_" + dimension.height + "_" + type; return id + "_" + dimension.width + "_" + dimension.height + "_" + type;
} }
/**
* 批量添加图标集
*
* @param sets 图标集
*/
public static void addSet(@NotNull List<IconSet> 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图标格式 * 是否SVG图标格式
* *

223
designer-base/src/main/java/com/fine/theme/icon/plugin/PluginIconManager.java

@ -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<String, List<IconSet>> SOURCE_ICON_MAPS = new ConcurrentHashMap<>(2);
private static final Map<String, HashMap<String, WeakReference<Icon>>> CACHE = new ConcurrentHashMap<>();
/**
* 获取图标集
*
* @param id 图标集ID
* @return 图标集
*/
public static IconSet getSet(String source, String id) {
List<IconSet> 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<IconSet> 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<IconSet> sets) {
removeSet(source);
addSet(source, sets);
}
/**
* 删除指定插件图标集
*
* @param source 插件
*/
public static void removeSet(@NotNull String source) {
SOURCE_ICON_MAPS.remove(source);
clearCacheBySource(source);
}
/**
* 根据图标ID获取图标
* <p>
* 查找路径
* 1查找图集图标
* 2路径为图片图标从路径再查找
* 3提供默认svg图标
*
* @param id 图标ID
* @param <I> 图标类型
* @return 图标
*/
@NotNull
public static <I extends Icon> 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 extends Icon> I findIcon(String source, String id, Dimension dimension, IconType type) {
String cacheKey = genCacheKey(source, id, dimension, type);
HashMap<String, WeakReference<Icon>> sourceCache = CACHE.getOrDefault(cacheKey, new HashMap<>(64));
final WeakReference<Icon> reference = sourceCache.get(cacheKey);
I icon = reference != null ? (I) reference.get() : null;
if (icon == null) {
List<IconSet> 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<IconSet> 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);
}
}

113
designer-base/src/main/java/com/fine/theme/icon/plugin/PluginJsonIconSet.java

@ -1,121 +1,22 @@
package com.fine.theme.icon.plugin; package com.fine.theme.icon.plugin;
import com.fine.theme.icon.AbstractIconSet; import com.fine.theme.icon.JsonIconSet;
import com.fine.theme.icon.IconType;
import com.fine.theme.icon.UrlIconResource; 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 图标集
* json 格式参考 fine_light.icon.json
* 为了保证 插件之间插件与设计器 icon id 的唯一性icons key 值规则参考 {@link PluginListIconSet}
* *
* @author lemon * @author lemon
* @since * @since
* Created on 2024/08/20 * Created on 2024/08/20
*/ */
public class PluginJsonIconSet extends AbstractIconSet { public class PluginJsonIconSet extends JsonIconSet {
private String base;
public PluginJsonIconSet(UrlIconResource resource) {
if (resource.getPath() == null) {
return;
}
Map<String, Object> json;
try (InputStream in = resource.getInputStream()) {
try (Reader reader = new InputStreamReader(in, StandardCharsets.UTF_8)) {
json = (Map<String, Object>) 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<String, Object> icons = (Map<String, Object>) json.get("icons");
for (Map.Entry<String, Object> icon : icons.entrySet()) {
applyIcon(icon.getKey(), icon.getValue());
}
public PluginJsonIconSet(String id, UrlIconResource resource) {
super(resource);
this.name = id;
} }
private void applyIcon(String key, Object value) {
if (value instanceof String) {
dealWithIconString(key, (String) value);
} else if (value instanceof Map) {
dealWithIconMap(key, (Map<String, Object>) value);
}
}
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<String, Object> 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);
}
} }

137
designer-base/src/main/java/com/fine/theme/icon/plugin/PluginLazyIcon.java

@ -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 extends Icon> 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();
}
}

57
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<String> icons) {
this.name = id;
addIconWithList(icons);
}
/**
* 根据 list 注册图标
* @param icons icon path list
*/
public void addIconWithList(List<String> 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);
}
}

54
designer-base/src/main/java/com/fine/theme/icon/plugin/PluginMapIconSet.java

@ -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<String, String> iconId2Path) {
addIconWithMap(iconId2Path);
}
/**
* 根据 map 注册图标
* @param iconId2Path key: id, value: icon path
*/
public void addIconWithMap(Map<String, String> iconId2Path) {
for (Map.Entry<String, String> 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);
}
}

5
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.icon.IconManager;
import com.fine.theme.light.ui.FineLightIconSet; import com.fine.theme.light.ui.FineLightIconSet;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
import com.fr.design.fun.LazyIconProvider;
import com.fr.stable.StringUtils; import com.fr.stable.StringUtils;
/** /**
@ -27,14 +26,14 @@ public class FineDarkLaf extends FineLaf {
*/ */
public static boolean setup() { public static boolean setup() {
IconManager.addSet(new FineLightIconSet()); IconManager.addSet(new FineLightIconSet());
// dark_icon 目前还没适配,先使用 light_icon
insertIconProvider(LazyIconProvider.THEME.LIGHT_ICON);
Layouts.setScaleFactor(UIScale.getUserScaleFactor()); Layouts.setScaleFactor(UIScale.getUserScaleFactor());
UIScale.addPropertyChangeListener(evt -> { UIScale.addPropertyChangeListener(evt -> {
if (StringUtils.equals(evt.getPropertyName(), USER_SCALE_FACTOR)) { if (StringUtils.equals(evt.getPropertyName(), USER_SCALE_FACTOR)) {
Layouts.setScaleFactor((float) evt.getNewValue()); Layouts.setScaleFactor((float) evt.getNewValue());
} }
}); });
// dark_icon 目前还没适配,先使用 light_icon
listenPluginIcons(false);
return setup(new FineDarkLaf()); return setup(new FineDarkLaf());
} }

55
designer-base/src/main/java/com/fine/theme/light/ui/laf/FineLaf.java

@ -1,16 +1,15 @@
package com.fine.theme.light.ui.laf; package com.fine.theme.light.ui.laf;
import com.fine.theme.icon.IconManager;
import com.fine.theme.icon.IconSet; import com.fine.theme.icon.IconSet;
import com.fine.theme.icon.UrlIconResource; 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.PluginJsonIconSet;
import com.fine.theme.icon.plugin.PluginMapIconSet; import com.fine.theme.icon.plugin.PluginListIconSet;
import com.formdev.flatlaf.FlatLaf; import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.util.SystemInfo; import com.formdev.flatlaf.util.SystemInfo;
import com.fr.design.ExtraDesignClassManager;
import com.fr.design.fun.LazyIconProvider; import com.fr.design.fun.LazyIconProvider;
import com.fr.general.ComparatorUtils;
import com.fr.general.GeneralContext; 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.manage.PluginFilter;
import com.fr.plugin.observer.PluginEvent; import com.fr.plugin.observer.PluginEvent;
import com.fr.plugin.observer.PluginEventListener; import com.fr.plugin.observer.PluginEventListener;
@ -35,25 +34,34 @@ public abstract class FineLaf extends FlatLaf {
private static final String NAME = "FineLaf"; private static final String NAME = "FineLaf";
private static void handlePluginEvent(PluginEvent event, LazyIconProvider.THEME category, private static void handlePluginEvent(PluginEvent event, boolean isDark,
BiConsumer<LazyIconProvider, List<IconSet>> operation) { BiConsumer<LazyIconProvider, List<IconSet>> operation) {
Set<LazyIconProvider> set = event.getContext().getRuntime().get(LazyIconProvider.MARK_STRING); Set<LazyIconProvider> set = event.getContext().getRuntime().get(LazyIconProvider.MARK_STRING);
dealWithPluginIcon(set, category, operation); dealWithPluginIcon(set, isDark, operation);
} }
private static void dealWithPluginIcon(Set<LazyIconProvider> set, LazyIconProvider.THEME category, private static void dealWithPluginIcon(Set<LazyIconProvider> set, boolean isDark,
BiConsumer<LazyIconProvider, List<IconSet>> operation) { BiConsumer<LazyIconProvider, List<IconSet>> operation) {
for (LazyIconProvider provider : set) { for (LazyIconProvider provider : set) {
if (!ComparatorUtils.equals(provider.themeCategory(), category)) { if (provider.isDark() != isDark) {
continue; continue;
} }
List<IconSet> iconSets = generatePluginIconSet(provider);
operation.accept(provider, iconSets);
}
}
private static List<IconSet> generatePluginIconSet(LazyIconProvider provider) {
List<IconSet> iconSets = new ArrayList<>(); List<IconSet> iconSets = new ArrayList<>();
PluginJsonIconSet jsonIconSet = new PluginJsonIconSet(new UrlIconResource(provider.jsonPath())); if (provider.jsonPath() != null) {
PluginJsonIconSet jsonIconSet = new PluginJsonIconSet(provider.id(), new UrlIconResource(provider.jsonPath()));
iconSets.add(jsonIconSet); iconSets.add(jsonIconSet);
PluginMapIconSet mapIconSet = new PluginMapIconSet(provider.iconId2Path());
iconSets.add(mapIconSet);
operation.accept(provider, iconSets);
} }
if (CollectionUtils.isNotEmpty(provider.icons())) {
PluginListIconSet listIconSet = new PluginListIconSet(provider.id(), provider.icons());
iconSets.add(listIconSet);
}
return iconSets;
} }
@Override @Override
@ -93,43 +101,28 @@ public abstract class FineLaf extends FlatLaf {
/** /**
* 适配插件图标 Icon * 适配插件图标 Icon
* @param category 图标 Icon 分类 {@link LazyIconProvider.THEME} * @param isDark 图标 Icon 主题light 或者 dark
*/ */
public static void insertIconProvider(LazyIconProvider.THEME category) { public static void listenPluginIcons(boolean isDark) {
Set<LazyIconProvider> 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) {
//注册插件监听 //注册插件监听
PluginFilter filter = context -> context.contain(LazyIconProvider.MARK_STRING); PluginFilter filter = context -> context.contain(LazyIconProvider.MARK_STRING);
PluginEventListener insert = new PluginEventListener() { PluginEventListener insert = new PluginEventListener() {
@Override @Override
public void on(PluginEvent event) { public void on(PluginEvent event) {
handlePluginEvent(event, category, (provider, iconSets) -> PluginIconManager.addSet(provider.pluginId(), iconSets)); handlePluginEvent(event, isDark, (provider, iconSets) -> IconManager.addSet(iconSets));
}
};
PluginEventListener update = new PluginEventListener() {
@Override
public void on(PluginEvent event) {
handlePluginEvent(event, category, (provider, iconSets) -> PluginIconManager.updateSet(provider.pluginId(), iconSets));
} }
}; };
PluginEventListener remove = new PluginEventListener() { PluginEventListener remove = new PluginEventListener() {
@Override @Override
public void on(PluginEvent event) { 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.AfterRun, insert, filter);
GeneralContext.listenPlugin(PluginEventType.AfterInstall, 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.AfterForbid, remove, filter);
GeneralContext.listenPlugin(PluginEventType.AfterUninstall, remove, filter); GeneralContext.listenPlugin(PluginEventType.AfterUninstall, remove, filter);
} }

3
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.icon.IconManager;
import com.fine.theme.light.ui.FineLightIconSet; import com.fine.theme.light.ui.FineLightIconSet;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
import com.fr.design.fun.LazyIconProvider;
import com.fr.stable.StringUtils; import com.fr.stable.StringUtils;
/** /**
@ -27,13 +26,13 @@ public class FineLightLaf extends FineLaf {
*/ */
public static boolean setup() { public static boolean setup() {
IconManager.addSet(new FineLightIconSet()); IconManager.addSet(new FineLightIconSet());
insertIconProvider(LazyIconProvider.THEME.LIGHT_ICON);
Layouts.setScaleFactor(UIScale.getUserScaleFactor()); Layouts.setScaleFactor(UIScale.getUserScaleFactor());
UIScale.addPropertyChangeListener(evt -> { UIScale.addPropertyChangeListener(evt -> {
if (StringUtils.equals(evt.getPropertyName(), USER_SCALE_FACTOR)) { if (StringUtils.equals(evt.getPropertyName(), USER_SCALE_FACTOR)) {
Layouts.setScaleFactor((float) evt.getNewValue()); Layouts.setScaleFactor((float) evt.getNewValue());
} }
}); });
listenPluginIcons(false);
return setup(new FineLightLaf()); return setup(new FineLightLaf());
} }

38
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 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 { public interface LazyIconProvider extends Mutable {
String MARK_STRING = "LazyIconProvider"; String MARK_STRING = "LazyIconProvider";
String DARK_SUFFIX = "_dark";
String LIGHT_SUFFIX = "_light";
int CURRENT_LEVEL = 1; int CURRENT_LEVEL = 1;
@ -30,39 +32,25 @@ public interface LazyIconProvider extends Mutable {
*/ */
String jsonPath(); String jsonPath();
/**
* 图标所属主题分类
*
* @return 主题类别
*/
THEME themeCategory();
/** /**
* 构建需要注册的图标 key: id, value: icon path * 构建需要注册的图标 key: id, value: icon path
* @return map * @return map
*/ */
Map<String, String> iconId2Path(); List<String> icons();
/**
* 图标主题
*/
enum THEME {
/** /**
* light_icon * 主题类别 light, dark
* @return 是否是 dark
*/ */
LIGHT_ICON("light_icon"), boolean isDark();
/** /**
* dark_icon * 插件注册的 iconSet id 根据主题设置为 pluginId_light 或者 pluginId_dark
* 同种主题内部的 iconSet id 不做区分
* @return iconSet id
*/ */
DARK_ICON("dark_icon") default String id() {
; String suffix = isDark() ? DARK_SUFFIX : LIGHT_SUFFIX;
return pluginId() + suffix;
final String category;
THEME(String category) {
this.category = category;
} }
}
} }

19
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.impl.AbstractProvider;
import com.fr.stable.fun.mark.API; import com.fr.stable.fun.mark.API;
import java.io.UnsupportedEncodingException; import java.util.List;
import java.net.URLDecoder;
import java.util.Map;
/** /**
@ -49,23 +47,18 @@ public class AbstractLazyIconProvider extends AbstractProvider implements LazyIc
} }
/** /**
* 图标主题 {@link THEME} * 直接注册图标元素是 icon path
* *
* @return 主题类别 * @return list
*/ */
@Override @Override
public THEME themeCategory() { public List<String> icons() {
return null; return null;
} }
/**
* 直接注册图标key icon id, value icon path
*
* @return map
*/
@Override @Override
public Map<String, String> iconId2Path() { public boolean isDark() {
return null; return false;
} }
} }

Loading…
Cancel
Save