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 @Immutable
public abstract class AbstractIconSource<I extends Icon> implements IconSource<I> { 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; protected String id;
@ -100,9 +100,11 @@ public abstract class AbstractIconSource<I extends Icon> implements IconSource<I
} }
if (resource instanceof UrlIconResource) { if (resource instanceof UrlIconResource) {
String disablePath = findDisablePath(((UrlIconResource) resource).getPath()); 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(grayResource, dimension, IconType.normal);
} }
}
return loadIcon(resource, dimension, IconType.disable); 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 path;
} }
/**
* 资源是否可访问
*
* @return 是否可访问
*/
public boolean isReachable() {
try (InputStream inputStream = getInputStream(path)) {
return inputStream != null;
} catch (Exception e) {
return false;
}
}
@Override @Override
@NotNull @NotNull
public InputStream getInputStream() { public InputStream getInputStream() {
InputStream inputStream = getInputStream(path); try (InputStream inputStream = getInputStream(path)) {
if (inputStream == null) { if (inputStream == null) {
throw new IconException("Icon load failed: " + path); throw new IconException("Icon load failed: " + path);
} }
return inputStream; 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; package com.fine.theme.icon.svg;
import com.fine.theme.icon.AbstractIconSource;
import com.fine.theme.icon.DisabledIcon; import com.fine.theme.icon.DisabledIcon;
import com.fine.theme.icon.GraphicsFilter; import com.fine.theme.icon.GraphicsFilter;
import com.fine.theme.icon.IconResource; import com.fine.theme.icon.IconResource;
import com.fine.theme.icon.IconType; import com.fine.theme.icon.IconType;
import com.fine.theme.icon.UrlIconResource;
import com.fine.theme.icon.WhiteIcon; import com.fine.theme.icon.WhiteIcon;
import com.formdev.flatlaf.FlatLaf; import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.ui.FlatUIUtils; import com.formdev.flatlaf.ui.FlatUIUtils;
@ -69,9 +71,30 @@ public class SvgIcon implements DisabledIcon, WhiteIcon, Icon {
g = grayGraphics(g); g = grayGraphics(g);
} }
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints(g); Object[] oldRenderingHints = FlatUIUtils.setRenderingHints(g);
render(c, g, x, y); try {
render(c, g, x, y, this::fallbackRender);
} finally {
FlatUIUtils.resetRenderingHints(g, oldRenderingHints); 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) { private Graphics2D grayGraphics(Graphics g) {
Object grayFilterObj = UIManager.get("Component.grayFilter"); Object grayFilterObj = UIManager.get("Component.grayFilter");
@ -92,7 +115,7 @@ public class SvgIcon implements DisabledIcon, WhiteIcon, Icon {
return scaleSize.height; 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 { try {
if (type == IconType.white) { if (type == IconType.white) {
Objects.requireNonNull(whiteSvgDocument.getValue()) Objects.requireNonNull(whiteSvgDocument.getValue())
@ -103,6 +126,7 @@ public class SvgIcon implements DisabledIcon, WhiteIcon, Icon {
} }
} catch (Exception e) { } catch (Exception e) {
FineLoggerFactory.getLogger().error("SvgIcon from url: " + resource + "can not paint.", 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() { public @NotNull SvgIcon disabled() {
return new SvgIcon(resource, size, IconType.disable); 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.ScaledEmptyBorder;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
import com.fr.design.gui.UILookAndFeel; import com.fr.design.gui.UILookAndFeel;
import com.fr.third.org.reflections.Reflections;
import com.fr.value.NotNullLazyValue; import com.fr.value.NotNullLazyValue;
import javax.swing.DefaultListCellRenderer; import javax.swing.DefaultListCellRenderer;
@ -29,11 +30,10 @@ import java.awt.BorderLayout;
import java.awt.Component; import java.awt.Component;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
import java.io.File;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static com.fine.swing.ui.layout.Layouts.cell; import static com.fine.swing.ui.layout.Layouts.cell;
@ -108,33 +108,30 @@ public class Storybook {
private StoryBookComponent[] components() { private StoryBookComponent[] components() {
ArrayList<StoryBookComponent> components = new ArrayList<>(); ArrayList<StoryBookComponent> components = new ArrayList<>();
for (String s : getClasses()) { List<Class<?>> componentList = getDebugClasses();
components.add(new StoryBookComponent(s.replace("StoryBoard", ""), COMPONENTS_PACKAGE + s)); 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]); return components.toArray(new StoryBookComponent[0]);
} }
private static List<String> getClasses() { private static List<Class<?>> getClasses() {
List<String> classNames = new ArrayList<>(); Reflections reflections = new Reflections("com.fr.design.gui.storybook.components");
URL resource = Storybook.class.getResource(COMPONENTS_DIR); Set<Class<?>> storyClass = reflections.getTypesAnnotatedWith(Story.class);
try { Set<Class<? extends StoryBoard>> classSet = reflections.getSubTypesOf(StoryBoard.class);
File folder = new File(resource.toURI()); storyClass.addAll(classSet);
File[] files = folder.listFiles(); return storyClass.stream().sorted(Comparator.comparing(Class::getSimpleName)).collect(Collectors.toList());
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<?>> 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