Browse Source

REPORT-114888 icon无法找到_disable图标时使用系统默认灰化图

newui
vito 6 months ago
parent
commit
dd7f075f16
  1. 6
      designer-base/src/main/java/com/fine/theme/icon/AbstractIconSource.java
  2. 18
      designer-base/src/main/java/com/fine/theme/icon/UrlIconResource.java
  3. 34
      designer-base/src/main/java/com/fine/theme/icon/svg/SvgIcon.java
  4. 21
      designer-base/src/test/java/com/fr/design/gui/storybook/DebugStory.java
  5. 45
      designer-base/src/test/java/com/fr/design/gui/storybook/Storybook.java

6
designer-base/src/main/java/com/fine/theme/icon/AbstractIconSource.java

@ -24,7 +24,7 @@ import java.awt.Dimension;
@Immutable
public abstract class AbstractIconSource<I extends Icon> implements IconSource<I> {
private static final String ICON_DISABLE_SUFFIX = "_disable";
public static final String ICON_DISABLE_SUFFIX = "_disable";
protected String id;
@ -100,9 +100,11 @@ public abstract class AbstractIconSource<I extends Icon> implements IconSource<I
}
if (resource instanceof UrlIconResource) {
String disablePath = findDisablePath(((UrlIconResource) resource).getPath());
grayResource = new UrlIconResource(disablePath);
UrlIconResource disableIconResource = new UrlIconResource(disablePath);
if (disableIconResource.isReachable()) {
return loadIcon(grayResource, dimension, IconType.normal);
}
}
return loadIcon(resource, dimension, IconType.disable);
}

18
designer-base/src/main/java/com/fine/theme/icon/UrlIconResource.java

@ -28,14 +28,30 @@ public class UrlIconResource implements IconResource {
return path;
}
/**
* 资源是否可访问
*
* @return 是否可访问
*/
public boolean isReachable() {
try (InputStream inputStream = getInputStream(path)) {
return inputStream != null;
} catch (Exception e) {
return false;
}
}
@Override
@NotNull
public InputStream getInputStream() {
InputStream inputStream = getInputStream(path);
try (InputStream inputStream = getInputStream(path)) {
if (inputStream == null) {
throw new IconException("Icon load failed: " + path);
}
return inputStream;
} catch (Exception e) {
throw new IconException("Icon load failed: " + path);
}
}

34
designer-base/src/main/java/com/fine/theme/icon/svg/SvgIcon.java

@ -1,9 +1,11 @@
package com.fine.theme.icon.svg;
import com.fine.theme.icon.AbstractIconSource;
import com.fine.theme.icon.DisabledIcon;
import com.fine.theme.icon.GraphicsFilter;
import com.fine.theme.icon.IconResource;
import com.fine.theme.icon.IconType;
import com.fine.theme.icon.UrlIconResource;
import com.fine.theme.icon.WhiteIcon;
import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.ui.FlatUIUtils;
@ -69,9 +71,30 @@ public class SvgIcon implements DisabledIcon, WhiteIcon, Icon {
g = grayGraphics(g);
}
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints(g);
render(c, g, x, y);
try {
render(c, g, x, y, this::fallbackRender);
} finally {
FlatUIUtils.resetRenderingHints(g, oldRenderingHints);
}
}
/**
* 用于fallback渲染disable图像这段代码来自异常分支使用率要保持较低水平
*/
private void fallbackRender(Component c, Graphics g, int x, int y) {
if (resource instanceof UrlIconResource) {
String path = ((UrlIconResource) resource).getPath();
String[] names = path.split(AbstractIconSource.ICON_DISABLE_SUFFIX);
if (path.contains(AbstractIconSource.ICON_DISABLE_SUFFIX) && names.length > 1) {
SVGLoader loader = new SVGLoader();
SVGDocument document = loader.load(new UrlIconResource(names[0] + names[1]).getInputStream());
if (document != null) {
document.render((JComponent) c, grayGraphics(g),
new ViewBox(x, y, scaleSize.width, scaleSize.height));
}
}
}
}
private Graphics2D grayGraphics(Graphics g) {
Object grayFilterObj = UIManager.get("Component.grayFilter");
@ -92,7 +115,7 @@ public class SvgIcon implements DisabledIcon, WhiteIcon, Icon {
return scaleSize.height;
}
private void render(Component c, Graphics g, int x, int y) {
private void render(Component c, Graphics g, int x, int y, FallbackRender fallbackRender) {
try {
if (type == IconType.white) {
Objects.requireNonNull(whiteSvgDocument.getValue())
@ -103,6 +126,7 @@ public class SvgIcon implements DisabledIcon, WhiteIcon, Icon {
}
} catch (Exception e) {
FineLoggerFactory.getLogger().error("SvgIcon from url: " + resource + "can not paint.", e);
fallbackRender.render(c, g, x, y);
}
}
@ -141,4 +165,10 @@ public class SvgIcon implements DisabledIcon, WhiteIcon, Icon {
public @NotNull SvgIcon disabled() {
return new SvgIcon(resource, size, IconType.disable);
}
@FunctionalInterface
interface FallbackRender {
void render(Component c, Graphics g, int x, int y);
}
}

21
designer-base/src/test/java/com/fr/design/gui/storybook/DebugStory.java

@ -0,0 +1,21 @@
package com.fr.design.gui.storybook;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 单面板调试注解如果components目录下带有这个注解
* 那么Storybook中只有带有这个注解的界面被展示
*
* @author vito
* @since 11.0
* Created on 2024/6/11
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
public @interface DebugStory {
}

45
designer-base/src/test/java/com/fr/design/gui/storybook/Storybook.java

@ -9,6 +9,7 @@ import com.formdev.flatlaf.extras.FlatAnimatedLafChange;
import com.formdev.flatlaf.util.ScaledEmptyBorder;
import com.formdev.flatlaf.util.UIScale;
import com.fr.design.gui.UILookAndFeel;
import com.fr.third.org.reflections.Reflections;
import com.fr.value.NotNullLazyValue;
import javax.swing.DefaultListCellRenderer;
@ -29,11 +30,10 @@ import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.io.File;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static com.fine.swing.ui.layout.Layouts.cell;
@ -108,33 +108,30 @@ public class Storybook {
private StoryBookComponent[] components() {
ArrayList<StoryBookComponent> components = new ArrayList<>();
for (String s : getClasses()) {
components.add(new StoryBookComponent(s.replace("StoryBoard", ""), COMPONENTS_PACKAGE + s));
List<Class<?>> componentList = getDebugClasses();
if (componentList.isEmpty()) {
componentList = getClasses();
}
for (Class<?> s : componentList) {
components.add(
new StoryBookComponent(s.getSimpleName().replace("StoryBoard", ""), s.getTypeName()));
}
return components.toArray(new StoryBookComponent[0]);
}
private static List<String> getClasses() {
List<String> classNames = new ArrayList<>();
URL resource = Storybook.class.getResource(COMPONENTS_DIR);
try {
File folder = new File(resource.toURI());
File[] files = folder.listFiles();
if (files != null) {
for (File file : files) {
if (file.isFile() && file.getName().endsWith(".class")) {
String className = file.getName().replace(".class", "");
if (isStory(className)) {
classNames.add(className);
}
}
}
}
return classNames.stream().sorted().collect(Collectors.toList());
} catch (URISyntaxException e) {
throw new RuntimeException(e);
private static List<Class<?>> getClasses() {
Reflections reflections = new Reflections("com.fr.design.gui.storybook.components");
Set<Class<?>> storyClass = reflections.getTypesAnnotatedWith(Story.class);
Set<Class<? extends StoryBoard>> classSet = reflections.getSubTypesOf(StoryBoard.class);
storyClass.addAll(classSet);
return storyClass.stream().sorted(Comparator.comparing(Class::getSimpleName)).collect(Collectors.toList());
}
private static List<Class<?>> getDebugClasses() {
Reflections reflections = new Reflections("com.fr.design.gui.storybook.components");
Set<Class<?>> types = reflections.getTypesAnnotatedWith(DebugStory.class);
return new ArrayList<>(types);
}
/**

Loading…
Cancel
Save