diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functioncompare/actions/CompareFunctionsAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functioncompare/actions/CompareFunctionsAction.java index c181972b84..3bab2121d1 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functioncompare/actions/CompareFunctionsAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functioncompare/actions/CompareFunctionsAction.java @@ -29,7 +29,7 @@ import ghidra.program.model.listing.Function; import ghidra.util.HelpLocation; import resources.MultiIcon; import resources.ResourceManager; -import resources.icons.ScaledImageIconWrapper; +import resources.icons.ScaledImageIcon; import resources.icons.TranslateIcon; /** @@ -48,7 +48,7 @@ public abstract class CompareFunctionsAction extends DockingAction { private static final ImageIcon COMPARISON_ICON = ResourceManager.loadImage("images/page_white_c.png"); private static final Icon NEW_ICON = ResourceManager.loadImage("images/bullet_star.png"); - private static final Icon SCALED_NEW_ICON = new ScaledImageIconWrapper(NEW_ICON, 16, 16); + private static final Icon SCALED_NEW_ICON = new ScaledImageIcon(NEW_ICON, 16, 16); private static final Icon TRANSLATED_NEW_ICON = new TranslateIcon(SCALED_NEW_ICON, 4, -4); private static final Icon CREATE_NEW_COMPARISON_ICON = new MultiIcon(COMPARISON_ICON, TRANSLATED_NEW_ICON); @@ -101,8 +101,7 @@ public abstract class CompareFunctionsAction extends DockingAction { setPopupMenuData(new MenuData(new String[] { "Compare Selected Functions" }, getToolBarIcon(), CREATE_COMPARISON_GROUP)); - ToolBarData newToolBarData = - new ToolBarData(getToolBarIcon(), CREATE_COMPARISON_GROUP); + ToolBarData newToolBarData = new ToolBarData(getToolBarIcon(), CREATE_COMPARISON_GROUP); setToolBarData(newToolBarData); setHelpLocation(new HelpLocation("FunctionComparison", "Function_Comparison")); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functioncompare/actions/OpenFunctionTableAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functioncompare/actions/OpenFunctionTableAction.java index afd9f3480f..b4f3e5cffa 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functioncompare/actions/OpenFunctionTableAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functioncompare/actions/OpenFunctionTableAction.java @@ -37,7 +37,7 @@ import ghidra.program.model.listing.Program; import ghidra.util.HelpLocation; import resources.MultiIcon; import resources.ResourceManager; -import resources.icons.ScaledImageIconWrapper; +import resources.icons.ScaledImageIcon; import resources.icons.TranslateIcon; import util.CollectionUtils; @@ -50,7 +50,7 @@ import util.CollectionUtils; public class OpenFunctionTableAction extends DockingAction { private static final Icon ADD_ICON = ResourceManager.loadImage("images/Plus.png"); - private static final Icon SCALED_ADD_ICON = new ScaledImageIconWrapper(ADD_ICON, 10, 10); + private static final Icon SCALED_ADD_ICON = new ScaledImageIcon(ADD_ICON, 10, 10); private static final ImageIcon COMPARISON_ICON = ResourceManager.loadImage("images/page_white_c.png"); private static final Icon TRANSLATED_ADD_ICON = new TranslateIcon(SCALED_ADD_ICON, 8, 1); diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/plugin/VTPlugin.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/plugin/VTPlugin.java index 8ea353eafc..d0ccbde7f8 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/plugin/VTPlugin.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/plugin/VTPlugin.java @@ -89,8 +89,8 @@ public class VTPlugin extends Plugin { protected Icon createIcon() { MultiIcon icon = new MultiIcon(new EmptyIcon(16, 16)); ImageIcon cancelIcon = ResourceManager.loadImage("images/dialog-cancel.png"); - ScaledImageIconWrapper scaledCancelIcon = - new ScaledImageIconWrapper(cancelIcon, 13, 13); + ScaledImageIcon scaledCancelIcon = + new ScaledImageIcon(cancelIcon, 13, 13); TranslateIcon translatedCancelIcon = new TranslateIcon(scaledCancelIcon, 3, 4); ImageIcon undoIcon = ResourceManager.loadImage("images/undo.png"); TranslateIcon translatedUndoIcon = new TranslateIcon(undoIcon, 0, -4); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/action/DockingAction.java b/Ghidra/Framework/Docking/src/main/java/docking/action/DockingAction.java index 97c657dcd7..b06989062b 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/action/DockingAction.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/action/DockingAction.java @@ -31,7 +31,6 @@ import ghidra.util.datastruct.WeakSet; import ghidra.util.exception.AssertException; import resources.ResourceManager; import resources.icons.FileBasedIcon; -import resources.icons.ImageIconWrapper; import utilities.util.reflection.ReflectionUtilities; /** @@ -493,9 +492,8 @@ public abstract class DockingAction implements DockingActionIf { } Icon icon = menuBarData.getMenuIcon(); - if (icon != null && icon instanceof ImageIconWrapper) { - ImageIconWrapper wrapper = (ImageIconWrapper) icon; - String filename = wrapper.getFilename(); + if (icon instanceof FileBasedIcon filebasedIcon) { + String filename = filebasedIcon.getFilename(); buffer.append(" MENU ICON: ").append(filename); buffer.append('\n'); } @@ -522,9 +520,8 @@ public abstract class DockingAction implements DockingActionIf { } Icon icon = popupMenuData.getMenuIcon(); - if (icon != null && icon instanceof ImageIconWrapper) { - ImageIconWrapper wrapper = (ImageIconWrapper) icon; - String filename = wrapper.getFilename(); + if (icon instanceof FileBasedIcon fileBasedIcon) { + String filename = fileBasedIcon.getFilename(); buffer.append(" POPUP ICON: ").append(filename); buffer.append('\n'); } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/util/BadgedIcon.java b/Ghidra/Framework/Docking/src/main/java/docking/util/BadgedIcon.java index 02402cf29c..c48cc0151e 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/util/BadgedIcon.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/util/BadgedIcon.java @@ -25,7 +25,7 @@ import javax.swing.ImageIcon; import resources.MultiIcon; import resources.ResourceManager; import resources.icons.EmptyIcon; -import resources.icons.ScaledImageIconWrapper; +import resources.icons.ScaledImageIcon; /** * An icon that allows sub-icons to be added at key perimeter locations. Each position can @@ -317,7 +317,7 @@ public class BadgedIcon implements Icon { MultiIcon icon = badgeMap.get(pos); - Icon scaled = new ScaledImageIconWrapper(icon, badgeSize.width, badgeSize.height); + Icon scaled = new ScaledImageIcon(icon, badgeSize.width, badgeSize.height); Point badgePaintLoc = getBadgePaintLocation(pos, badgeSize); diff --git a/Ghidra/Framework/Generic/src/main/java/resources/ResourceManager.java b/Ghidra/Framework/Generic/src/main/java/resources/ResourceManager.java index bb5eeb9750..808ffec712 100644 --- a/Ghidra/Framework/Generic/src/main/java/resources/ResourceManager.java +++ b/Ghidra/Framework/Generic/src/main/java/resources/ResourceManager.java @@ -324,7 +324,7 @@ public class ResourceManager { * @return A new, scaled ImageIcon */ public static ImageIcon getScaledIcon(Icon icon, int width, int height, int hints) { - return new ScaledImageIconWrapper(icon, width, height, hints); + return new ScaledImageIcon(icon, width, height, hints); } /** @@ -337,7 +337,7 @@ public class ResourceManager { * @return A new, scaled ImageIcon */ public static ImageIcon getScaledIcon(Icon icon, int width, int height) { - return new ScaledImageIconWrapper(icon, width, height); + return new ScaledImageIcon(icon, width, height); } /** @@ -346,7 +346,7 @@ public class ResourceManager { * @return disabled icon */ public static ImageIcon getDisabledIcon(Icon icon) { - return new DisabledImageIconWrapper(getImageIcon(icon)); + return new DisabledImageIcon(icon); } /** @@ -355,7 +355,7 @@ public class ResourceManager { * @return disabled icon */ public static ImageIcon getDisabledIcon(ImageIcon icon) { - return new DisabledImageIconWrapper(icon); + return new DisabledImageIcon(icon); } /** @@ -367,7 +367,7 @@ public class ResourceManager { * @return a disabled version of the original icon. */ public static ImageIcon getDisabledIcon(Icon icon, int brightnessPercent) { - return new DisabledImageIconWrapper(icon, brightnessPercent); + return new DisabledImageIcon(icon, brightnessPercent); } /** @@ -381,7 +381,7 @@ public class ResourceManager { * @return the new icon */ public static ImageIcon getImageIconFromImage(String imageName, Image image) { - return new ImageIconWrapper(image, imageName); + return new DerivedImageIcon(imageName, image); } /** @@ -396,7 +396,7 @@ public class ResourceManager { if (icon instanceof ImageIcon) { return (ImageIcon) icon; } - return new ImageIconWrapper(icon); + return new DerivedImageIcon(icon); } /** @@ -452,7 +452,7 @@ public class ResourceManager { if (icon != null) { return icon; } - icon = new ImageIconWrapper(imageBytes, imageName); + icon = new BytesImageIcon(imageName, imageBytes); iconMap.put(imageName, icon); return icon; } @@ -476,39 +476,47 @@ public class ResourceManager { /** * Load the image specified by filename; returns the default bomb icon * if problems occur trying to load the file. - *
*
* @param filename name of file to load, e.g., "images/home.gif"
* @return the image icon stored in the bytes
*/
public static ImageIcon loadImage(String filename) {
-
- // use the wrapper so that images are not loaded until they are needed
ImageIcon icon = iconMap.get(filename);
- if (icon != null) {
- return icon;
+ if (icon == null) {
+ icon = doLoadIcon(filename, ResourceManager.getDefaultIcon());
+ iconMap.put(filename, icon);
+ }
+ return icon;
+ }
+
+ private static ImageIcon doLoadIcon(String filename, ImageIcon defaultIcon) {
+ // if only the name of an icon is given, but not a path, check to see if it is
+ // a resource that lives under our "images/" folder
+ if (!filename.contains("/")) {
+ URL url = getResource("images/" + filename);
+ if (url != null) {
+ return new UrlImageIcon(filename, url);
+ }
}
+ // look for it directly with the given path
+ URL url = getResource(filename);
+ if (url != null) {
+ return new UrlImageIcon(filename, url);
+ }
+
+ // try using the filename as a file path
File imageFile = new File(filename);
if (imageFile.exists()) {
try {
- icon = new ImageIconWrapper(imageFile.toURI().toURL());
- iconMap.put(filename, icon);
- return icon;
+ return new UrlImageIcon(filename, imageFile.toURI().toURL());
}
catch (MalformedURLException e) {
// handled below
}
}
- URL url = getResource(filename);
- if (url != null) {
- icon = new ImageIconWrapper(url);
- iconMap.put(filename, icon);
- return icon;
- }
-
- return getDefaultIcon();
+ return defaultIcon;
}
/**
@@ -547,7 +555,7 @@ public class ResourceManager {
Msg.error(ResourceManager.class,
"Could not find default icon: " + DEFAULT_ICON_FILENAME);
}
- DEFAULT_ICON = new ImageIconWrapper(url);
+ DEFAULT_ICON = new UrlImageIcon(DEFAULT_ICON_FILENAME, url);
}
return DEFAULT_ICON;
}
diff --git a/Ghidra/Framework/Generic/src/main/java/resources/icons/BytesImageIcon.java b/Ghidra/Framework/Generic/src/main/java/resources/icons/BytesImageIcon.java
new file mode 100644
index 0000000000..35702038bb
--- /dev/null
+++ b/Ghidra/Framework/Generic/src/main/java/resources/icons/BytesImageIcon.java
@@ -0,0 +1,49 @@
+/* ###
+ * IP: GHIDRA
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package resources.icons;
+
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.util.Objects;
+
+import javax.swing.ImageIcon;
+
+import generic.util.image.ImageUtils;
+
+/**
+ * {@link LazyImageIcon} that is created from a byte array
+ */
+public class BytesImageIcon extends LazyImageIcon {
+ private byte[] bytes;
+
+ public BytesImageIcon(String name, byte[] imageBytes) {
+ super(name);
+ this.bytes = Objects.requireNonNull(imageBytes);
+ }
+
+ protected ImageIcon createImageIcon() {
+ String name = getFilename();
+ Image image = createImage();
+ if (!ImageUtils.waitForImage(name, image)) {
+ return null;
+ }
+ return new ImageIcon(image, name);
+ }
+
+ protected Image createImage() {
+ return Toolkit.getDefaultToolkit().createImage(bytes);
+ }
+}
diff --git a/Ghidra/Framework/Generic/src/main/java/resources/icons/DerivedImageIcon.java b/Ghidra/Framework/Generic/src/main/java/resources/icons/DerivedImageIcon.java
new file mode 100644
index 0000000000..61ffd4800d
--- /dev/null
+++ b/Ghidra/Framework/Generic/src/main/java/resources/icons/DerivedImageIcon.java
@@ -0,0 +1,80 @@
+/* ###
+ * IP: GHIDRA
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package resources.icons;
+
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.image.BufferedImage;
+import java.util.Objects;
+
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+
+import generic.util.image.ImageUtils;
+import resources.ResourceManager;
+
+/**
+ * {@link LazyImageIcon} that is created from an {@link Icon} or an {@link Image}
+ */
+public class DerivedImageIcon extends LazyImageIcon {
+ private Icon sourceIcon;
+ private Image sourceImage;
+
+ /**
+ * Constructor for deriving from an icon
+ * @param icon the source icon
+ */
+ public DerivedImageIcon(Icon icon) {
+ super(ResourceManager.getIconName(icon));
+ this.sourceIcon = Objects.requireNonNull(icon);
+ }
+
+ /**
+ * Constructor for deriving from an image
+ * @param name the name of the image
+ * @param image the source image
+ */
+ public DerivedImageIcon(String name, Image image) {
+ super(name);
+ this.sourceImage = Objects.requireNonNull(image);
+ }
+
+ protected ImageIcon createImageIcon() {
+ Image image = createImage();
+ String imageName = getFilename();
+ if (!ImageUtils.waitForImage(imageName, image)) {
+ return null;
+ }
+ return new ImageIcon(image, imageName);
+ }
+
+ protected Image createImage() {
+ if (sourceImage != null) {
+ return sourceImage;
+ }
+
+ // if sourceImage is null, then sourceIcon can't be null
+ if (sourceIcon instanceof ImageIcon) {
+ return ((ImageIcon) sourceIcon).getImage();
+ }
+ BufferedImage bufferedImage = new BufferedImage(sourceIcon.getIconWidth(),
+ sourceIcon.getIconHeight(), BufferedImage.TYPE_INT_ARGB);
+ Graphics graphics = bufferedImage.getGraphics();
+ sourceIcon.paintIcon(null, graphics, 0, 0);
+ graphics.dispose();
+ return bufferedImage;
+ }
+}
diff --git a/Ghidra/Framework/Generic/src/main/java/resources/icons/DisabledImageIcon.java b/Ghidra/Framework/Generic/src/main/java/resources/icons/DisabledImageIcon.java
new file mode 100644
index 0000000000..58d519bb4f
--- /dev/null
+++ b/Ghidra/Framework/Generic/src/main/java/resources/icons/DisabledImageIcon.java
@@ -0,0 +1,64 @@
+/* ###
+ * IP: GHIDRA
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package resources.icons;
+
+import java.awt.Image;
+
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+
+import generic.util.image.ImageUtils;
+
+/**
+ * {@link LazyImageIcon} that creates a disabled version of an icon
+ */
+public class DisabledImageIcon extends DerivedImageIcon {
+
+ /**
+ * The inverse percentage of gray (higher percentage equals less gray) to apply to
+ * the disabled image; higher is brighter
+ */
+ private int brightnessPercent;
+
+ /**
+ * Construct wrapped disabled ImageIcon based upon specified baseIcon.
+ * A 50% brightness will be applied.
+ * @param baseIcon enabled icon to be rendered as disabled
+ */
+ public DisabledImageIcon(Icon baseIcon) {
+ this(baseIcon, 50); // default to half gray
+ }
+
+ /**
+ * Construct wrapped disabled ImageIcon based upon specified baseIcon
+ * using the specified brightness level
+ * @param baseIcon the icon to create a disabled version of
+ * @param brightnessPercent a brightness level specified using a
+ * value in the range of 0 thru 100.
+ */
+ public DisabledImageIcon(Icon baseIcon, int brightnessPercent) {
+ super(baseIcon);
+ this.brightnessPercent = brightnessPercent;
+ }
+
+ @Override
+ protected ImageIcon createImageIcon() {
+ Image image = createImage();
+ Image disabledImage = ImageUtils.createDisabledImage(image, brightnessPercent);
+ return new ImageIcon(disabledImage, getFilename());
+ }
+
+}
diff --git a/Ghidra/Framework/Generic/src/main/java/resources/icons/DisabledImageIconWrapper.java b/Ghidra/Framework/Generic/src/main/java/resources/icons/DisabledImageIconWrapper.java
index 145d7b504c..5068474817 100644
--- a/Ghidra/Framework/Generic/src/main/java/resources/icons/DisabledImageIconWrapper.java
+++ b/Ghidra/Framework/Generic/src/main/java/resources/icons/DisabledImageIconWrapper.java
@@ -22,6 +22,12 @@ import javax.swing.ImageIcon;
import generic.util.image.ImageUtils;
+/**
+ * Creates a disabled version of an icon
+ * @deprecated This class has been replaced by {@link DisabledImageIcon} since it
+ * extends {@link ImageIconWrapper} which has also been deprecated.
+ */
+@Deprecated(forRemoval = true, since = "11")
public class DisabledImageIconWrapper extends ImageIconWrapper {
/**
diff --git a/Ghidra/Framework/Generic/src/main/java/resources/icons/ImageIconWrapper.java b/Ghidra/Framework/Generic/src/main/java/resources/icons/ImageIconWrapper.java
index cde7aba68c..be3bd7c11e 100644
--- a/Ghidra/Framework/Generic/src/main/java/resources/icons/ImageIconWrapper.java
+++ b/Ghidra/Framework/Generic/src/main/java/resources/icons/ImageIconWrapper.java
@@ -36,7 +36,13 @@ import resources.ResourceManager;
* it has the added benefit of allowing the use of static initialization
* of ImageIcons without starting the Swing thread which can cause
* problems when running headless.
+ *
+ * @deprecated This class has been replaced by a series of classes that extend
+ * {@link LazyImageIcon}: {@link UrlImageIcon}, {@link DerivedImageIcon}, {@link BytesImageIcon},
+ * {@link DisabledImageIcon}, and {@link ScaledImageIcon}. Pick the one that matches
+ * the constructor that was being used to create an ImageIconWrapper
*/
+@Deprecated(forRemoval = true, since = "11")
public class ImageIconWrapper extends ImageIcon implements FileBasedIcon {
private boolean loaded;
diff --git a/Ghidra/Framework/Generic/src/main/java/resources/icons/LazyImageIcon.java b/Ghidra/Framework/Generic/src/main/java/resources/icons/LazyImageIcon.java
new file mode 100644
index 0000000000..8c02405404
--- /dev/null
+++ b/Ghidra/Framework/Generic/src/main/java/resources/icons/LazyImageIcon.java
@@ -0,0 +1,134 @@
+/* ###
+ * IP: GHIDRA
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package resources.icons;
+
+import java.awt.*;
+import java.awt.image.ImageObserver;
+
+import javax.accessibility.AccessibleContext;
+import javax.swing.ImageIcon;
+
+import resources.ResourceManager;
+
+/**
+ * LazyImageIcon
provides the ability to instantiate
+ * an ImageIcon with delayed loading. In addition to delayed loading
+ * it has the added benefit of allowing the use of static initialization
+ * of ImageIcons without starting the Swing thread which can cause
+ * problems when running headless.
+ */
+public abstract class LazyImageIcon extends ImageIcon implements FileBasedIcon {
+
+ private boolean loaded;
+
+ protected LazyImageIcon(String name) {
+ setDescription(name);
+ }
+
+ private synchronized void init() {
+ if (!loaded) {
+ loaded = true;
+ ImageIcon imageIcon = createImageIcon();
+ if (imageIcon == null) {
+ imageIcon = getDefaultIcon();
+ }
+ super.setImage(imageIcon.getImage());
+ super.setDescription(getDescription());
+ }
+ }
+
+ protected abstract ImageIcon createImageIcon();
+
+ @Override
+ public String getFilename() {
+ return getDescription();
+ }
+
+ @Override
+ public Image getImage() {
+ init();
+ return super.getImage();
+ }
+
+ @Override
+ public AccessibleContext getAccessibleContext() {
+ init();
+ return super.getAccessibleContext();
+ }
+
+ @Override
+ public String getDescription() {
+ init();
+ return super.getDescription();
+ }
+
+ @Override
+ public int getIconHeight() {
+ init();
+ return super.getIconHeight();
+ }
+
+ @Override
+ public int getIconWidth() {
+ init();
+ return super.getIconWidth();
+ }
+
+ @Override
+ public int getImageLoadStatus() {
+ init();
+ return super.getImageLoadStatus();
+ }
+
+ @Override
+ public ImageObserver getImageObserver() {
+ init();
+ return super.getImageObserver();
+ }
+
+ @Override
+ public synchronized void paintIcon(Component c, Graphics g, int x, int y) {
+ init();
+ super.paintIcon(c, g, x, y);
+ }
+
+ @Override
+ public void setDescription(String description) {
+ super.setDescription(description);
+ }
+
+ @Override
+ public void setImage(Image image) {
+ init();
+ super.setImage(image);
+ }
+
+ @Override
+ public String toString() {
+ init();
+ return super.toString();
+ }
+
+ private ImageIcon getDefaultIcon() {
+ ImageIcon defaultIcon = ResourceManager.getDefaultIcon();
+ if (this == defaultIcon) {
+ // this can happen under just the right conditions when loading the default
+ // icon's bytes fails (probably due to disk or network issues)
+ throw new IllegalStateException("Unexpected failure loading the default icon!");
+ }
+ return defaultIcon; // some sort of initialization has failed
+ }
+}
diff --git a/Ghidra/Framework/Generic/src/main/java/resources/icons/ScaledImageIcon.java b/Ghidra/Framework/Generic/src/main/java/resources/icons/ScaledImageIcon.java
new file mode 100644
index 0000000000..1f60529a32
--- /dev/null
+++ b/Ghidra/Framework/Generic/src/main/java/resources/icons/ScaledImageIcon.java
@@ -0,0 +1,68 @@
+/* ###
+ * IP: GHIDRA
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package resources.icons;
+
+import java.awt.*;
+
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+
+import generic.util.image.ImageUtils;
+
+/**
+ * {@link LazyImageIcon} that creates a scaled version of an icon
+ */
+public class ScaledImageIcon extends DerivedImageIcon {
+
+ private int width;
+ private int height;
+ private int hints;
+
+ /**
+ * Construct wrapped scaled ImageIcon based upon specified
+ * baseIcon and desired size. The rendering hints of
+ * {@link Image#SCALE_AREA_AVERAGING} will be applied.
+ * @param baseIcon base icon
+ * @param width new icon width
+ * @param height new icon height
+ */
+ public ScaledImageIcon(Icon baseIcon, int width, int height) {
+ this(baseIcon, width, height, Image.SCALE_AREA_AVERAGING);
+ }
+
+ /**
+ * Construct wrapped scaled ImageIcon based upon specified
+ * baseIcon and desired size
+ * @param baseIcon base icon
+ * @param width new icon width
+ * @param height new icon height
+ * @param hints {@link RenderingHints} used by {@link Graphics2D}
+ */
+ public ScaledImageIcon(Icon baseIcon, int width, int height, int hints) {
+ super(baseIcon);
+ this.width = width;
+ this.height = height;
+ this.hints = hints;
+ }
+
+ @Override
+ protected ImageIcon createImageIcon() {
+ Image image = createImage();
+ Image scaledImage = ImageUtils.createScaledImage(image, width, height, hints);
+ return new ImageIcon(scaledImage, getFilename());
+ }
+
+}
diff --git a/Ghidra/Framework/Generic/src/main/java/resources/icons/ScaledImageIconWrapper.java b/Ghidra/Framework/Generic/src/main/java/resources/icons/ScaledImageIconWrapper.java
index e5dca1e7fa..7ab34eef3a 100644
--- a/Ghidra/Framework/Generic/src/main/java/resources/icons/ScaledImageIconWrapper.java
+++ b/Ghidra/Framework/Generic/src/main/java/resources/icons/ScaledImageIconWrapper.java
@@ -22,6 +22,12 @@ import javax.swing.ImageIcon;
import generic.util.image.ImageUtils;
+/**
+ * Creates a scaled version of an icon
+ * @deprecated This class has been replaced by {@link ScaledImageIcon} since it
+ * extends {@link ImageIconWrapper} which has also been deprecated.
+ */
+@Deprecated(forRemoval = true, since = "11")
public class ScaledImageIconWrapper extends ImageIconWrapper {
private int width;
diff --git a/Ghidra/Framework/Generic/src/main/java/resources/icons/UrlImageIcon.java b/Ghidra/Framework/Generic/src/main/java/resources/icons/UrlImageIcon.java
new file mode 100644
index 0000000000..9312d6ffe9
--- /dev/null
+++ b/Ghidra/Framework/Generic/src/main/java/resources/icons/UrlImageIcon.java
@@ -0,0 +1,80 @@
+/* ###
+ * IP: GHIDRA
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package resources.icons;
+
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.io.*;
+import java.net.URL;
+import java.util.Objects;
+
+import javax.swing.ImageIcon;
+
+import generic.util.image.ImageUtils;
+import ghidra.util.Msg;
+
+/**
+ * {@link LazyImageIcon} that is created from a URL to an icon file.
+ */
+public class UrlImageIcon extends LazyImageIcon {
+ private URL imageURL;
+
+ /**
+ * Constructor
+ * @param path the path String used to create the URL
+ * @param url the {@link URL} to an icon resource file
+ */
+ public UrlImageIcon(String path, URL url) {
+ super(path);
+ this.imageURL = Objects.requireNonNull(url);
+ }
+
+ protected ImageIcon createImageIcon() {
+ String name = getFilename();
+ Image image = createImage();
+ if (image == null) {
+ return null;
+ }
+ if (!ImageUtils.waitForImage(name, image)) {
+ return null;
+ }
+ return new ImageIcon(image, name);
+ }
+
+ protected Image createImage() {
+ byte[] imageBytes = loadBytesFromURL(imageURL);
+ if (imageBytes == null) {
+ return null;
+ }
+ return Toolkit.getDefaultToolkit().createImage(imageBytes);
+ }
+
+ private byte[] loadBytesFromURL(URL url) {
+ try (InputStream is = url.openStream()) {
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ int length = 0;
+ byte[] buf = new byte[1024];
+ while ((length = is.read(buf)) > 0) {
+ os.write(buf, 0, length);
+ }
+ return os.toByteArray();
+ }
+ catch (IOException e) {
+ Msg.error(this, "Exception loading image bytes: " + url.toExternalForm(), e);
+ }
+ return null;
+ }
+}