Updated the help system to share code for finding runtime icons

This commit is contained in:
dragonmacher 2023-02-14 12:32:46 -05:00
parent 956673ebed
commit e7a031ff8e
3 changed files with 88 additions and 88 deletions

View file

@ -15,6 +15,9 @@
*/ */
package generic.theme; package generic.theme;
import java.awt.Color;
import java.awt.Font;
import ghidra.util.Msg; import ghidra.util.Msg;
/** /**
@ -41,8 +44,35 @@ public class HeadlessThemeManager extends ThemeManager {
} }
private void doInitialize() { private void doInitialize() {
initializeSystemValues();
buildCurrentValues(); buildCurrentValues();
GColor.refreshAll(currentValues); GColor.refreshAll(currentValues);
GIcon.refreshAll(currentValues); GIcon.refreshAll(currentValues);
} }
private void initializeSystemValues() {
//
// These values may be referenced by Java clients. The headless env does not load the
// Java LookAndFeel, which is from where the values are usually defined. So, add dummy
// definitions for these values here.
//
Font font = new Font("Arial", Font.PLAIN, 12);
javaDefaults.addFont(new FontValue(SystemThemeIds.FONT_CONTROL_ID, font));
javaDefaults.addFont(new FontValue(SystemThemeIds.FONT_VIEW_ID, font));
javaDefaults.addFont(new FontValue(SystemThemeIds.FONT_MENU_ID, font));
javaDefaults.addColor(new ColorValue(SystemThemeIds.BG_CONTROL_ID, Color.CYAN));
javaDefaults.addColor(new ColorValue(SystemThemeIds.BG_VIEW_ID, Color.CYAN));
javaDefaults.addColor(new ColorValue(SystemThemeIds.BG_TOOLTIP_ID, Color.CYAN));
javaDefaults.addColor(new ColorValue(SystemThemeIds.BG_VIEW_SELECTED_ID, Color.CYAN));
javaDefaults.addColor(new ColorValue(SystemThemeIds.BG_BORDER_ID, Color.CYAN));
javaDefaults.addColor(new ColorValue(SystemThemeIds.FG_CONTROL_ID, Color.CYAN));
javaDefaults.addColor(new ColorValue(SystemThemeIds.FG_VIEW_ID, Color.CYAN));
javaDefaults.addColor(new ColorValue(SystemThemeIds.FG_TOOLTIP_ID, Color.CYAN));
javaDefaults.addColor(new ColorValue(SystemThemeIds.FG_VIEW_SELECTED_ID, Color.CYAN));
javaDefaults.addColor(new ColorValue(SystemThemeIds.FG_DISABLED_ID, Color.CYAN));
}
} }

View file

@ -26,7 +26,6 @@ import java.util.Map;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.swing.Icon;
import javax.swing.JEditorPane; import javax.swing.JEditorPane;
import javax.swing.event.HyperlinkEvent; import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener; import javax.swing.event.HyperlinkListener;
@ -35,8 +34,8 @@ import javax.swing.text.html.*;
import javax.swing.text.html.HTML.Tag; import javax.swing.text.html.HTML.Tag;
import generic.jar.ResourceFile; import generic.jar.ResourceFile;
import generic.theme.*; import generic.theme.GColor;
import generic.theme.GThemeDefaults.Colors; import generic.theme.Gui;
import ghidra.framework.Application; import ghidra.framework.Application;
import ghidra.framework.preferences.Preferences; import ghidra.framework.preferences.Preferences;
import ghidra.util.Msg; import ghidra.util.Msg;
@ -471,11 +470,6 @@ public class GHelpHTMLEditorKit extends HTMLEditorKit {
*/ */
private class GHelpImageView extends ImageView { private class GHelpImageView extends ImageView {
private static final String HELP_SHARED_ARROW = "help/shared/arrow.gif";
private static final Icon SHARED_ARROW_ICON = new HelpRightArrowIcon(Colors.FOREGROUND);
private static final IconProvider SHARED_ARROW_ICON_PROVIDER =
new IconProvider(SHARED_ARROW_ICON, null);
/* /*
* Unusual Code Alert! * Unusual Code Alert!
* This class exists to enable our help system to find custom icons defined in source * This class exists to enable our help system to find custom icons defined in source
@ -547,61 +541,15 @@ public class GHelpHTMLEditorKit extends HTMLEditorKit {
return null; return null;
} }
//
// This code is looking for the specific referenced image file and then replacing that
// image file with something that can update its content at runtime, based on theme.
// Alternatively, we could have updated all help files to point to a GIcon, which
// handles updating itself when the theme changes. We chose to replace the icon here
// instead of in the source code to prevent changing many files.
//
String srcString = src.toString().trim(); String srcString = src.toString().trim();
if (srcString.equals(HELP_SHARED_ARROW)) { IconProvider iconProvider = HelpBuildUtils.getRuntimeIcon(srcString);
return installImageFromCustomIcon(SHARED_ARROW_ICON_PROVIDER); if (iconProvider != null && !iconProvider.isInvalid()) {
} // note: store the image off for later use; the url will not be used by us
this.image = iconProvider.getImage();
// check if the srcString is a defined theme icon id
if (Gui.hasIcon(srcString)) {
//
// Wrap the GIcon inside of an IconProvider, as that class can handle a null URL
// returned from GIcon. (This can happen if the GIcon is based on a modified icon.)
//
GIcon gIcon = new GIcon(srcString);
IconProvider iconProvider = new IconProvider(gIcon, gIcon.getUrl());
return iconProvider.getOrCreateUrl(); return iconProvider.getOrCreateUrl();
} }
if (isJavaCode(srcString)) { return doGetImageURL(srcString);
return installImageFromJavaCode(srcString);
}
URL url = doGetImageURL(srcString);
return url;
}
private URL installImageFromCustomIcon(IconProvider iconProvider) {
if (iconProvider == null || iconProvider.isInvalid()) {
return null;
}
this.image = iconProvider.getImage();
// note: this icon is not used to load the image; the 'image' we set is used instead
URL url = iconProvider.getOrCreateUrl();
return url;
}
private URL installImageFromJavaCode(String srcString) {
IconProvider iconProvider = getIconFromJavaCode(srcString);
if (iconProvider == null || iconProvider.isInvalid()) {
return null;
}
this.image = iconProvider.getImage();
URL url = iconProvider.getOrCreateUrl();
return url;
} }
private URL doGetImageURL(String srcString) { private URL doGetImageURL(String srcString) {
@ -624,16 +572,6 @@ public class GHelpHTMLEditorKit extends HTMLEditorKit {
URL resource = ResourceManager.getResource(srcString); URL resource = ResourceManager.getResource(srcString);
return resource; return resource;
} }
private boolean isJavaCode(String src) {
// not sure of the best way to handle this--be exact for now
return Icons.isIconsReference(src);
}
private IconProvider getIconFromJavaCode(String src) {
return Icons.getIconForIconsReference(src);
}
} }
} }

View file

@ -23,8 +23,11 @@ import java.util.Collections;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.swing.Icon;
import generic.jar.ResourceFile; import generic.jar.ResourceFile;
import generic.theme.GIcon; import generic.theme.GIcon;
import generic.theme.GThemeDefaults.Colors;
import generic.theme.Gui; import generic.theme.Gui;
import ghidra.framework.Application; import ghidra.framework.Application;
import ghidra.util.HelpLocation; import ghidra.util.HelpLocation;
@ -44,6 +47,11 @@ public class HelpBuildUtils {
public static boolean debug = true; public static boolean debug = true;
private static final String HELP_SHARED_ARROW = "help/shared/arrow.gif";
private static final Icon SHARED_ARROW_ICON = new HelpRightArrowIcon(Colors.FOREGROUND);
private static final IconProvider SHARED_ARROW_ICON_PROVIDER =
new IconProvider(SHARED_ARROW_ICON, null);
private HelpBuildUtils() { private HelpBuildUtils() {
// utils class; can't create // utils class; can't create
} }
@ -491,6 +499,45 @@ public class HelpBuildUtils {
return null; return null;
} }
public static IconProvider getRuntimeIcon(String ref) {
if (Icons.isIconsReference(ref)) {
// help system syntax: <img src="Icons.ERROR_ICON" />
IconProvider iconProvider = Icons.getIconForIconsReference(ref);
if (iconProvider == null) {
return new IconProvider(null, null); // return a non-null 'invalid' provider
}
return iconProvider;
}
if (Gui.hasIcon(ref)) {
//
// Wrap the GIcon inside of an IconProvider, as that class can handle a null URL
// returned from GIcon. (This can happen if the GIcon is based on a modified icon.)
//
GIcon gIcon = new GIcon(ref);
return new IconProvider(gIcon, gIcon.getUrl());
}
//
// Handle any hard-coded special cases
//
//
// This code is looking for the specific referenced image file and then replacing that
// image file with something that can update its content at runtime, based on theme.
// Alternatively, we could have updated all help files to point to a GIcon, which
// handles updating itself when the theme changes. We chose to replace the icon here
// instead of in the source code to prevent changing many files.
//
String srcString = ref.toString().trim();
if (srcString.equals(HELP_SHARED_ARROW)) {
return SHARED_ARROW_ICON_PROVIDER;
}
return null;
}
/** /**
* Turn an HTML IMG reference into a location object that has resolved path info. This will * Turn an HTML IMG reference into a location object that has resolved path info. This will
* locate files based upon relative references, specialized help system references (i.e., * locate files based upon relative references, specialized help system references (i.e.,
@ -504,16 +551,14 @@ public class HelpBuildUtils {
public static ImageLocation locateImageReference(Path sourceFile, String ref) public static ImageLocation locateImageReference(Path sourceFile, String ref)
throws URISyntaxException { throws URISyntaxException {
if (Icons.isIconsReference(ref)) { IconProvider runtimeIconProvider = getRuntimeIcon(ref);
if (runtimeIconProvider != null) {
// help system syntax: <img src="Icons.ERROR_ICON" /> if (runtimeIconProvider.isInvalid()) {
IconProvider iconProvider = Icons.getIconForIconsReference(ref);
if (iconProvider == null || iconProvider.isInvalid()) {
// bad icon name // bad icon name
return ImageLocation.createInvalidRuntimeLocation(sourceFile, ref); return ImageLocation.createInvalidRuntimeLocation(sourceFile, ref);
} }
URL url = iconProvider.getUrl(); URL url = runtimeIconProvider.getUrl();
URI resolved = null; URI resolved = null;
Path path = null; Path path = null;
if (url != null) { // we may have an icon with an invalid URL (e.g., a MultiIcon) if (url != null) { // we may have an icon with an invalid URL (e.g., a MultiIcon)
@ -522,19 +567,6 @@ public class HelpBuildUtils {
} }
return ImageLocation.createRuntimeLocation(sourceFile, ref, resolved, path); return ImageLocation.createRuntimeLocation(sourceFile, ref, resolved, path);
} }
if (Gui.hasIcon(ref)) {
//
// Wrap the GIcon inside of an IconProvider, as that class can handle a null URL
// returned from GIcon. (This can happen if the GIcon is based on a modified icon.)
//
GIcon gIcon = new GIcon(ref);
IconProvider iconProvider = new IconProvider(gIcon, gIcon.getUrl());
URL url = iconProvider.getOrCreateUrl();
URI resolved = url.toURI();
Path path = toPath(resolved);
return ImageLocation.createRuntimeLocation(sourceFile, ref, resolved, path);
}
URI resolved = resolve(sourceFile, ref); URI resolved = resolve(sourceFile, ref);
if (isRemote(resolved)) { if (isRemote(resolved)) {