diff --git a/apisupport/apisupport.project/nbproject/project.xml b/apisupport/apisupport.project/nbproject/project.xml index ab1b49c87362..51236ea8107d 100644 --- a/apisupport/apisupport.project/nbproject/project.xml +++ b/apisupport/apisupport.project/nbproject/project.xml @@ -260,7 +260,7 @@ - 9.3 + 9.36 diff --git a/apisupport/apisupport.project/src/org/netbeans/modules/apisupport/project/layers/BadgingSupport.java b/apisupport/apisupport.project/src/org/netbeans/modules/apisupport/project/layers/BadgingSupport.java index 01ed998180cc..0c953d5b363d 100644 --- a/apisupport/apisupport.project/src/org/netbeans/modules/apisupport/project/layers/BadgingSupport.java +++ b/apisupport/apisupport.project/src/org/netbeans/modules/apisupport/project/layers/BadgingSupport.java @@ -20,7 +20,6 @@ package org.netbeans.modules.apisupport.project.layers; import java.awt.Image; -import java.awt.Toolkit; import java.beans.BeanInfo; import java.io.IOException; import java.io.InputStream; @@ -64,6 +63,7 @@ import org.openide.loaders.DataObject; import org.openide.loaders.InstanceDataObject; import org.openide.util.Exceptions; +import org.openide.util.ImageUtilities; import org.openide.util.Mutex; import org.openide.util.NbBundle; import org.openide.util.NbCollections; @@ -373,7 +373,7 @@ private Image annotateIconGeneral(Image icon, boolean big, Set - 9.3 + 9.36 diff --git a/ide/editor.lib/src/org/netbeans/editor/AnnotationType.java b/ide/editor.lib/src/org/netbeans/editor/AnnotationType.java index c49c9ffcf799..a9571e755e0f 100644 --- a/ide/editor.lib/src/org/netbeans/editor/AnnotationType.java +++ b/ide/editor.lib/src/org/netbeans/editor/AnnotationType.java @@ -26,10 +26,12 @@ import java.awt.Image; import java.awt.Toolkit; import java.awt.image.ImageObserver; +import java.net.URISyntaxException; import java.net.URL; import java.util.ResourceBundle; import java.util.logging.Level; import java.util.logging.Logger; +import org.openide.util.ImageUtilities; /** Definition of the annotation type. Annotation type is defined by attributes like * highlight color, foreground color, glyph icon, etc. Each annotation added to document @@ -156,7 +158,12 @@ public void setGlyph(java.net.URL glyph) { */ public Image getGlyphImage() { if (img == null) { - img = Toolkit.getDefaultToolkit().createImage(getGlyph()); + try { + img = ImageUtilities.loadImage(getGlyph().toURI()); + } catch (URISyntaxException e) { + LOG.log(Level.WARNING, "getGlyph() returned invalid URI", e); + return null; + } final boolean waiting[] = new boolean [1]; waiting[0] = true; if (!Toolkit.getDefaultToolkit().prepareImage(img, -1, -1, new ImageObserver() { diff --git a/ide/editor/nbproject/project.xml b/ide/editor/nbproject/project.xml index dcde4e549084..e6d84100af88 100644 --- a/ide/editor/nbproject/project.xml +++ b/ide/editor/nbproject/project.xml @@ -239,7 +239,7 @@ - 9.31 + 9.36 diff --git a/ide/editor/src/org/netbeans/modules/editor/options/AnnotationTypesNode.java b/ide/editor/src/org/netbeans/modules/editor/options/AnnotationTypesNode.java index 1579cde1eb8d..cf5ae45c2ebd 100644 --- a/ide/editor/src/org/netbeans/modules/editor/options/AnnotationTypesNode.java +++ b/ide/editor/src/org/netbeans/modules/editor/options/AnnotationTypesNode.java @@ -20,14 +20,12 @@ package org.netbeans.modules.editor.options; import java.awt.Image; -import java.awt.Toolkit; import org.openide.util.Exceptions; import org.openide.util.HelpCtx; import org.openide.util.ImageUtilities; import org.openide.util.actions.SystemAction; import org.openide.actions.PropertiesAction; import org.openide.nodes.Children; -import org.netbeans.modules.editor.options.AnnotationTypesFolder; import org.netbeans.editor.AnnotationType; import org.openide.nodes.AbstractNode; import org.openide.nodes.BeanNode; @@ -40,7 +38,10 @@ import java.lang.Boolean; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeEvent; +import java.net.URISyntaxException; import java.net.URL; +import java.util.logging.Level; +import java.util.logging.Logger; /** Node representing the Annotation Types in Options window. * @@ -48,7 +49,7 @@ * @since 07/2001 */ public class AnnotationTypesNode extends AbstractNode { - + private static final Logger LOGGER = Logger.getLogger(AnnotationTypesNode.class.getName()); private static final String HELP_ID = "editing.configuring.annotations"; // !!! NOI18N private static final String ICON_BASE = "org/netbeans/modules/editor/resources/annotationtypes"; // NOI18N @@ -196,12 +197,11 @@ public AnnotationTypesSubnode(AnnotationType type) throws IntrospectionException } public Image getIcon(int type) { - // Utilities.loadImage does not handle URLs. - // Toolkit.getImage would work, but U.lI does nicer caching. - if (iconURL.getProtocol().equals("nbresloc")) { // NOI18N - return ImageUtilities.loadImage(iconURL.getPath().substring(1)); - } else { - return Toolkit.getDefaultToolkit().getImage(iconURL); + try { + return ImageUtilities.loadImage(iconURL.toURI()); + } catch (URISyntaxException e) { + LOGGER.log(Level.WARNING, "AnnotationType.getGlyph() returned invalid URI", e); + return super.getIcon(type); } } diff --git a/ide/options.editor/nbproject/project.xml b/ide/options.editor/nbproject/project.xml index 917da4fb1353..4f97c52683e1 100644 --- a/ide/options.editor/nbproject/project.xml +++ b/ide/options.editor/nbproject/project.xml @@ -215,7 +215,7 @@ - 9.3 + 9.36 diff --git a/ide/options.editor/src/org/netbeans/modules/options/colors/ColorModel.java b/ide/options.editor/src/org/netbeans/modules/options/colors/ColorModel.java index dc983032708b..c439bf4e1a58 100644 --- a/ide/options.editor/src/org/netbeans/modules/options/colors/ColorModel.java +++ b/ide/options.editor/src/org/netbeans/modules/options/colors/ColorModel.java @@ -25,9 +25,9 @@ import java.awt.Cursor; import java.awt.Image; import java.awt.Rectangle; -import java.awt.Toolkit; import java.io.IOException; import java.io.InputStreamReader; +import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; import java.util.Collection; @@ -38,7 +38,6 @@ import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; -import javax.swing.ImageIcon; import javax.swing.JEditorPane; import javax.swing.JPanel; import javax.swing.SwingUtilities; @@ -134,14 +133,13 @@ private List processAnnotations(Map annos, b category.addAttribute(StyleConstants.NameAttribute, annotationType.getName()); URL iconURL = annotationType.getGlyph (); - Image image = null; - if (iconURL.getProtocol ().equals ("nbresloc")) { // NOI18N - image = ImageUtilities.loadImage(iconURL.getPath().substring(1)); - } else { - image = Toolkit.getDefaultToolkit ().getImage (iconURL); - } - if (image != null) { - category.addAttribute("icon", new ImageIcon(image)); //NOI18N + try { + Image image = ImageUtilities.loadImage(iconURL.toURI()); + if (image != null) { + category.addAttribute("icon", ImageUtilities.image2Icon(image)); //NOI18N + } + } catch (URISyntaxException e) { + LOG.log(Level.WARNING, "AnnotationType.getGlyph() returned invalid URI", e); } Color bgColor = annotationType.getHighlight(); diff --git a/java/form/nbproject/project.xml b/java/form/nbproject/project.xml index b3196b2c5b84..36910d8db322 100644 --- a/java/form/nbproject/project.xml +++ b/java/form/nbproject/project.xml @@ -189,7 +189,7 @@ - 9.3 + 9.36 diff --git a/java/form/src/org/netbeans/modules/form/palette/PaletteItemDataObject.java b/java/form/src/org/netbeans/modules/form/palette/PaletteItemDataObject.java index 207dda60ffdf..208a0a042358 100644 --- a/java/form/src/org/netbeans/modules/form/palette/PaletteItemDataObject.java +++ b/java/form/src/org/netbeans/modules/form/palette/PaletteItemDataObject.java @@ -22,6 +22,8 @@ import java.util.*; import java.io.*; import java.beans.*; +import java.net.URI; +import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; import org.openide.util.ImageUtilities; @@ -423,10 +425,9 @@ private java.awt.Image getExplicitIcon(int type) { { if (icon32URL != null) { // explicit icon specified in file try { - return java.awt.Toolkit.getDefaultToolkit().getImage( - new java.net.URL(icon32URL)); + return ImageUtilities.loadImage(new URI(icon32URL)); } - catch (java.net.MalformedURLException ex) {} // ignore + catch (URISyntaxException ex) {} // ignore } else if (getPrimaryFile().getAttribute("SystemFileSystem.icon32") != null) // NOI18N return super.getIcon(type); @@ -434,10 +435,9 @@ else if (getPrimaryFile().getAttribute("SystemFileSystem.icon32") != null) // NO else { // get small icon in other cases if (icon16URL != null) { // explicit icon specified in file try { - return java.awt.Toolkit.getDefaultToolkit().getImage( - new java.net.URL(icon16URL)); + return ImageUtilities.loadImage(new URI(icon16URL)); } - catch (java.net.MalformedURLException ex) {} // ignore + catch (URISyntaxException ex) {} // ignore } else if (getPrimaryFile().getAttribute("SystemFileSystem.icon") != null) // NOI18N return super.getIcon(type); diff --git a/java/performance/actionsframework/src/org/netbeans/actions/simple/Interpreter.java b/java/performance/actionsframework/src/org/netbeans/actions/simple/Interpreter.java index 3c1c32c8dc82..786cd6cd01cb 100644 --- a/java/performance/actionsframework/src/org/netbeans/actions/simple/Interpreter.java +++ b/java/performance/actionsframework/src/org/netbeans/actions/simple/Interpreter.java @@ -19,9 +19,12 @@ package org.netbeans.actions.simple; +import jakarta.websocket.ContainerProvider; +import java.awt.Image; import java.awt.Toolkit; import java.awt.event.KeyEvent; -import java.io.File; +import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; @@ -31,13 +34,12 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.Stack; import java.util.StringTokenizer; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.KeyStroke; -import org.netbeans.actions.spi.ActionProvider; -import org.netbeans.actions.spi.ContainerProvider; +import org.netbeans.spi.project.ActionProvider; +import org.openide.util.ImageUtilities; import org.openide.xml.XMLUtil; import org.xml.sax.*; import org.xml.sax.helpers.XMLReaderAdapter; @@ -253,9 +255,9 @@ public Icon getIconForAction (String action) { int idx = s.lastIndexOf("/"); String urlString = s.substring(0, idx) + "/" + partialPath; try { - URL url = new URL (urlString); - return new ImageIcon(Toolkit.getDefaultToolkit().getImage(url)); - } catch (Exception e) { + Image image = ImageUtilities.loadImage(new URI(urlString)); + return image == null ? new ImageIcon() : ImageUtilities.image2Icon(image); + } catch (URISyntaxException e) { e.printStackTrace(); } } diff --git a/java/performance/nbproject/project.xml b/java/performance/nbproject/project.xml index 20f1d1007d27..0126e5db6eae 100644 --- a/java/performance/nbproject/project.xml +++ b/java/performance/nbproject/project.xml @@ -99,7 +99,7 @@ - 9.3 + 9.36 diff --git a/platform/core.kit/test/perf/src/org/openide/filesystems/data/JavaSrc.java b/platform/core.kit/test/perf/src/org/openide/filesystems/data/JavaSrc.java index ba857ef36a9a..f26975dd0572 100644 --- a/platform/core.kit/test/perf/src/org/openide/filesystems/data/JavaSrc.java +++ b/platform/core.kit/test/perf/src/org/openide/filesystems/data/JavaSrc.java @@ -136,27 +136,6 @@ static final class ActionItemNode extends FilterNode { super(filter, Children.LEAF); } - /* - public Image getIcon (int type) { - if ((type == java.beans.BeanInfo.ICON_COLOR_16x16) || - (type == java.beans.BeanInfo.ICON_MONO_16x16)) { - if (itemIcon == null) - itemIcon = Toolkit.getDefaultToolkit ().getImage ( - getClass ().getResource ("/org/netbeans/core/resources/action.gif")); // NOI18N - return itemIcon; - } else { - if (itemIcon32 == null) - itemIcon32 = Toolkit.getDefaultToolkit ().getImage ( - getClass ().getResource ("/org/netbeans/core/resources/action32.gif")); // NOI18N - return itemIcon32; - } - } - - public Image getOpenedIcon (int type) { - return getIcon (type); - } - */ - /** Actions. * @return array of actions for this node */ diff --git a/platform/o.n.core/test/unit/data/projects/sfs-attr-test/sfs_attr_test/Util.java b/platform/o.n.core/test/unit/data/projects/sfs-attr-test/sfs_attr_test/Util.java index 752eb1aad9d2..5a2656014887 100644 --- a/platform/o.n.core/test/unit/data/projects/sfs-attr-test/sfs_attr_test/Util.java +++ b/platform/o.n.core/test/unit/data/projects/sfs-attr-test/sfs_attr_test/Util.java @@ -29,6 +29,7 @@ public abstract class Util { private Util() {} + // Called by reflection via registration in platform/o.n.core/test/unit/data/projects/sfs-attr-test/sfs_attr_test/layer.xml private static Image mergeIcons(FileObject fo) throws IOException { int count = ((Integer)fo.getAttribute("iconCount")).intValue(); if (count < 2) throw new IOException(); diff --git a/platform/openide.awt/nbproject/project.xml b/platform/openide.awt/nbproject/project.xml index 0398c101d6c4..5f274abf29a2 100644 --- a/platform/openide.awt/nbproject/project.xml +++ b/platform/openide.awt/nbproject/project.xml @@ -47,7 +47,7 @@ - 9.12 + 9.36 diff --git a/platform/openide.awt/src/org/openide/awt/AlwaysEnabledAction.java b/platform/openide.awt/src/org/openide/awt/AlwaysEnabledAction.java index f9c23926d7f5..fc5084895f25 100644 --- a/platform/openide.awt/src/org/openide/awt/AlwaysEnabledAction.java +++ b/platform/openide.awt/src/org/openide/awt/AlwaysEnabledAction.java @@ -26,6 +26,7 @@ import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.net.URISyntaxException; import java.net.URL; import java.util.Collection; import java.util.Map; @@ -227,7 +228,11 @@ static final Object extractCommonAttribute(Map fo, String name) { return (Icon) icon; } if (icon instanceof URL) { - icon = Toolkit.getDefaultToolkit().getImage((URL)icon); + try { + icon = ImageUtilities.loadImage(((URL)icon).toURI()); + } catch (URISyntaxException e) { + LOG.log(Level.WARNING, "SMALL_ICON attribute had invalid URI", e); + } } if (icon instanceof Image) { return ImageUtilities.image2Icon((Image)icon); diff --git a/platform/openide.filesystems.compat8/nbproject/project.xml b/platform/openide.filesystems.compat8/nbproject/project.xml index 10309267869d..1040bc33d9aa 100644 --- a/platform/openide.filesystems.compat8/nbproject/project.xml +++ b/platform/openide.filesystems.compat8/nbproject/project.xml @@ -62,7 +62,7 @@ - 9.3 + 9.36 diff --git a/platform/openide.filesystems.compat8/src/org/openide/filesystems/FileSystemCompat.java b/platform/openide.filesystems.compat8/src/org/openide/filesystems/FileSystemCompat.java index fdc9c7f20872..97542672f643 100644 --- a/platform/openide.filesystems.compat8/src/org/openide/filesystems/FileSystemCompat.java +++ b/platform/openide.filesystems.compat8/src/org/openide/filesystems/FileSystemCompat.java @@ -20,15 +20,16 @@ package org.openide.filesystems; import java.awt.Image; -import java.awt.Toolkit; import java.beans.BeanInfo; import java.beans.PropertyChangeListener; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.net.URISyntaxException; import java.net.URL; import java.util.Set; +import java.util.logging.Level; import static org.openide.filesystems.FileSystem.LOG; import org.openide.modules.PatchFor; import org.openide.util.Exceptions; @@ -284,7 +285,11 @@ private Image annotateIcon(FileObject fo, int type) { Object value = fo.getAttribute(attr); if (value != null) { if (value instanceof URL) { - return Toolkit.getDefaultToolkit().getImage((URL) value); + try { + return ImageUtilities.loadImage(((URL) value).toURI()); + } catch (URISyntaxException e) { + LOG.log(Level.WARNING, "Annotation has invalid icon URI", e); + } } else if (value instanceof Image) { // #18832 return (Image) value; diff --git a/platform/openide.filesystems.nb/nbproject/project.xml b/platform/openide.filesystems.nb/nbproject/project.xml index 92387bec9609..a7b79f34a332 100644 --- a/platform/openide.filesystems.nb/nbproject/project.xml +++ b/platform/openide.filesystems.nb/nbproject/project.xml @@ -54,7 +54,7 @@ - 9.3 + 9.36 diff --git a/platform/openide.filesystems.nb/src/org/netbeans/modules/openide/filesystems/FileSystemStatus.java b/platform/openide.filesystems.nb/src/org/netbeans/modules/openide/filesystems/FileSystemStatus.java index 9d5b2da312df..b38ff6841501 100644 --- a/platform/openide.filesystems.nb/src/org/netbeans/modules/openide/filesystems/FileSystemStatus.java +++ b/platform/openide.filesystems.nb/src/org/netbeans/modules/openide/filesystems/FileSystemStatus.java @@ -20,8 +20,8 @@ package org.netbeans.modules.openide.filesystems; import java.awt.Image; -import java.awt.Toolkit; import java.beans.BeanInfo; +import java.net.URISyntaxException; import java.net.URL; import java.util.Arrays; import java.util.MissingResourceException; @@ -117,7 +117,11 @@ private Image annotateIcon(FileObject fo, int type) { Object value = fo.getAttribute(attr); if (value != null) { if (value instanceof URL) { - return Toolkit.getDefaultToolkit().getImage((URL) value); + try { + return ImageUtilities.loadImage(((URL) value).toURI()); + } catch (URISyntaxException e) { + LOG.log(Level.WARNING, "Annotation has invalid icon URI", e); + } } else if (value instanceof Image) { // #18832 return (Image) value; diff --git a/platform/openide.filesystems/nbproject/project.xml b/platform/openide.filesystems/nbproject/project.xml index 3b8b4cc6aeda..4e8e4b639ea1 100644 --- a/platform/openide.filesystems/nbproject/project.xml +++ b/platform/openide.filesystems/nbproject/project.xml @@ -41,6 +41,14 @@ 8.17 + + org.openide.util.ui + + + + 9.36 + + diff --git a/platform/openide.filesystems/src/org/openide/filesystems/FileSystem.java b/platform/openide.filesystems/src/org/openide/filesystems/FileSystem.java index bb9bd0ec159f..cf298713c856 100644 --- a/platform/openide.filesystems/src/org/openide/filesystems/FileSystem.java +++ b/platform/openide.filesystems/src/org/openide/filesystems/FileSystem.java @@ -854,49 +854,5 @@ private String warningMessage(String name, FileObject fo) { } return "Cannot load " + name + " for " + fo + " defined by " + by; // NOI18N } - - /* - public Image annotateIcon(Image im, int type, Set files) { - for (FileObject fo : files) { - Image img = annotateIcon(fo, type); - if (img != null) { - return img; - } - } - return im; - } - - private Image annotateIcon(FileObject fo, int type) { - String attr = null; - if (type == BeanInfo.ICON_COLOR_16x16) { - attr = "SystemFileSystem.icon"; // NOI18N - } else if (type == BeanInfo.ICON_COLOR_32x32) { - attr = "SystemFileSystem.icon32"; // NOI18N - } - if (attr != null) { - Object value = fo.getAttribute(attr); - if (value != null) { - if (value instanceof URL) { - return Toolkit.getDefaultToolkit().getImage((URL) value); - } else if (value instanceof Image) { - // #18832 - return (Image) value; - } else { - LOG.warning("Attribute " + attr + " on " + fo + " expected to be a URL or Image; was: " + value); - } - } - } - String base = (String) fo.getAttribute("iconBase"); // NOI18N - if (base != null) { - if (type == BeanInfo.ICON_COLOR_16x16) { - return ImageUtilities.loadImage(base, true); - } else if (type == BeanInfo.ICON_COLOR_32x32) { - return ImageUtilities.loadImage(insertBeforeSuffix(base, "_32"), true); // NOI18N - } - } - return null; - } - */ - }; } diff --git a/platform/openide.util.ui/apichanges.xml b/platform/openide.util.ui/apichanges.xml index baed377a7a47..94169749edcb 100644 --- a/platform/openide.util.ui/apichanges.xml +++ b/platform/openide.util.ui/apichanges.xml @@ -27,6 +27,20 @@ Actions API + + + Added methods to ImageUtilities, to aid migration from other icon loading methods. + + + + + +

Added new utility methods to ImageUtilities to ease migration from other image loading methods used throughout the NetBeans codebase. + Loading icons via ImageUtilities is preferred as it permits alternative SVG versions to be loaded automatically when available.

+
+ +
+ Added methods to query mouse event pseudo-keycodes diff --git a/platform/openide.util.ui/src/org/openide/util/ImageUtilities.java b/platform/openide.util.ui/src/org/openide/util/ImageUtilities.java index 526f659594a8..eddc1d968a99 100644 --- a/platform/openide.util.ui/src/org/openide/util/ImageUtilities.java +++ b/platform/openide.util.ui/src/org/openide/util/ImageUtilities.java @@ -42,6 +42,8 @@ import java.io.ObjectOutputStream; import java.io.ObjectStreamException; import java.lang.ref.SoftReference; +import java.net.MalformedURLException; +import java.net.URI; import java.net.URL; import java.util.HashMap; import java.util.HashSet; @@ -161,8 +163,13 @@ private ImageUtilities() { } /** - * Loads an image from the specified resource ID. The image is loaded using the "system" classloader registered in - * Lookup. + * Loads an image from the specified resource path. The image is loaded using the "system" + * classloader registered in Lookup. + * + *

If the current look and feel is 'dark' (UIManager.getBoolean("nb.dark.theme")) + * then the method first attempts to load image + * <original file name>_dark.<original extension>. If such file + * doesn't exist the default one is loaded instead. * *

If the default lookup contains a service provider for the {@link SVGLoader} interface, and * there exists an SVG version of the requested image (e.g. "icon.svg" exists when "icon.png" @@ -177,6 +184,13 @@ private ImageUtilities() { * When painting on HiDPI-capable {@code Graphics2D} instances provided by Swing, the * appropriate transform will already be in place. * + *

Since version 8.12 the returned image object responds to call + * image.getProperty({@link #PROPERTY_URL}, null) by returning the internal + * {@link URL} of the found and loaded resource. The convenience method + * {@link #findImageBaseURL} should be used in preference to direct property access. + * + *

Caching of loaded images can be used internally to improve performance. + * * @param resourceID resource path of the icon (no initial slash) * @return icon's Image, or null, if the icon cannot be loaded. */ @@ -185,31 +199,93 @@ public static final Image loadImage(String resourceID) { } /** - * Loads an image based on resource path. + * Loads an image based on a resource path. * Exactly like {@link #loadImage(String)} but may do a localized search. * For example, requesting org/netbeans/modules/foo/resources/foo.gif * might actually find org/netbeans/modules/foo/resources/foo_ja.gif * or org/netbeans/modules/foo/resources/foo_mybranding.gif. - * - *

Caching of loaded images can be used internally to improve performance. - *

Since version 8.12 the returned image object responds to call - * image.getProperty({@link #PROPERTY_URL}, null) by returning the internal - * {@link URL} of the found and loaded resource. Convenience method {@link #findImageBaseURL} - * should be used in preference to direct property access. - * - *

If the current look and feel is 'dark' (UIManager.getBoolean("nb.dark.theme")) - * then the method first attempts to load image <original file name>_dark.<original extension>. - * If such file doesn't exist the default one is loaded instead. - *

- * + * * @param resource resource path of the image (no initial slash) * @param localized true for localized search - * @return icon's Image or null if the icon cannot be loaded + * @return the icon's Image, or null if the icon cannot be loaded */ public static final Image loadImage(String resource, boolean localized) { return loadImageInternal(resource, localized); } + /** + * Load an image from a URI/URL. If the URI uses the {@code nbresloc} protocol, it is loaded + * using the resource loading mechanism provided by {@link #loadImage(java.lang.String)}. This + * includes handling of SVG icons and dark mode variations. + * + *

This method is intended for use only when a URL or URI must be used instead of a resource + * path, e.g. in the implementation of pre-existing NetBeans APIs. External URLs should be + * avoided, as they may be disallowed in the future. Do not use this method for new code; prefer + * image loading by resource paths instead (e.g. {@link #loadImage(String)}). + * + * @param uri the URI of the image, possibly with the nbresloc protocol + * @return the loaded image, or either null or an uninitialized image if the image was not + * available + * @since 7.36 + */ + public static final Image loadImage(URI uri) { + Parameters.notNull("icon", uri); + String scheme = uri.getScheme(); + if (scheme.equals("nbresloc")) { // NOI18N + // Apply our dedicated handling logic. Omit the initial slash of the path. + return loadImage(uri.getPath().substring(1), false); + } else { + if (!(scheme.equals("file") || + scheme.equals("jar") && uri.toString().startsWith("jar:file:") || + scheme.equals("file"))) + { + LOGGER.log(Level.WARNING, "loadImage(URI) called with unusual URI: {0}", uri); + } + try { + /* Observed to return an image with size (-1, -1) if URL points to a non-existent + file (after ensureLoaded(Image) is called). */ + return Toolkit.getDefaultToolkit().createImage(uri.toURL()); + } catch (MalformedURLException e) { + LOGGER.log(Level.WARNING, "Malformed URL passed to loadImage(URI)", e); + return null; + } + } + } + + /** + * Convert an {@link Icon} instance to a delegating {@link ImageIcon} instance. If the supplied + * Icon instance is an SVG icon or has other HiDPI capabilities provided by the methods in this + * class, they are preserved by the conversion. + * + *

This method is intended for use only when existing APIs require the use of ImageIcon. In + * most other situations it is preferable to use the more general Icon type. + * + * @param icon the icon to be converted; may not be null + * @return the converted instance + * @since 7.36 + */ + public static final ImageIcon icon2ImageIcon(Icon icon) { + if (icon == null) { + /* Log a warning and return null rather than throwing an exception here. That way, + refactoring of existing code that wraps an existing expression in icon2ImageIcon will + not break existing functionality even if it accidentally relied on being able to pass + null in the past. */ + LOGGER.log(Level.WARNING, "Passing null to icon2ImageIcon is not permitted", + new NullPointerException()); + return null; + } + if (icon instanceof ImageIcon) { + return (ImageIcon) icon; + } else if (icon instanceof ToolTipImage) { + return ((ToolTipImage) icon).asImageIcon(); + } else { + Image image = icon2Image(icon); + ToolTipImage tti = (image instanceof ToolTipImage) + ? (ToolTipImage) image : assignToolTipToImageInternal(image, ""); + return tti.asImageIcon(); + } + } + /* Private version of the method showing the more specific return type. We always return a ToolTipImage, to take advantage of its rendering tweaks for HiDPI screens. */ private static ToolTipImage loadImageInternal(String resource, boolean localized) { @@ -235,16 +311,15 @@ private static ToolTipImage loadImageInternal(String resource, boolean localized } /** - * Loads an icon based on resource path. - * Similar to {@link #loadImage(String, boolean)}, returns ImageIcon instead of Image. - * - *

If the current look and feel is 'dark' (UIManager.getBoolean("nb.dark.theme")) - * then the method first attempts to load image <original file name>_dark.<original extension>. - * If such file doesn't exist the default one is loaded instead. - *

+ * Loads an icon based on a resource path. Similar to {@link #loadImage(String, boolean)}, but + * returns {@link ImageIcon} instead of {@link Image}. + * + *

When a general Icon instance can be used rather than more specifically an ImageIcon, it is + * recommended to use {@link #loadIcon(java.lang.String, boolean)} instead. This method remains + * for compatibility. * * @param resource resource path of the icon (no initial slash) - * @param localized localized resource should be used + * @param localized true for localized search * @return ImageIcon or null, if the icon cannot be loaded. * @since 7.22 */ @@ -255,6 +330,35 @@ public static final ImageIcon loadImageIcon( String resource, boolean localized } return image.asImageIcon(); } + + /** + * Loads an icon based on a resource path. Similar to {@link #loadImage(String, boolean)}, but + * returns {@link Icon} instead of {@link Image}. + * + * @param resource resource path of the icon (no initial slash) + * @param localized true for localized search + * @return ImageIcon or null, if the icon cannot be loaded. + * @since 7.36 + */ + public static final Icon loadIcon( String resource, boolean localized ) { + ToolTipImage image = loadImageInternal(resource, localized); + if( image == null ) { + return null; + } + return image.asImageIconIfRequiredForRetina(); + } + + /** + * Loads an icon based on a resource path. Similar to {@link #loadImage(String)}, but returns + * {@link Icon} instead of {@link Image}. + * + * @param resource resource path of the icon (no initial slash) + * @return ImageIcon or null, if the icon cannot be loaded. + * @since 7.36 + */ + public static final Icon loadIcon( String resource ) { + return loadIcon(resource, false); + } private static boolean isDarkLaF() { return UIManager.getBoolean("nb.dark.theme"); //NOI18N @@ -284,12 +388,14 @@ private static RGBImageFilter getImageIconFilter() { return imageIconFilter; } - /** This method merges two images into the new one. The second image is drawn + /** This method merges two images into the a one. The second image is drawn * over the first one with its top-left corner at x, y. Images need not be of the same size. - * New image will have a size of max(second image size + top-left corner, first image size). - * Method is used mostly when second image contains transparent pixels (e.g. for badging). - * Method that attempts to find the merged image in the cache first, then - * creates the image if it was not found. + * The new image will have a size of max(second image size + top-left corner, first image size). + * This method is used mostly when second image contains transparent pixels (e.g. for badging). + * + *

The implementation attempts to find the merged image in the cache first, then creates the + * image if it was not found. + * * @param image1 underlying image * @param image2 second image * @param x x position of top-left corner @@ -316,8 +422,34 @@ public static final Image mergeImages(Image image1, Image image2, int x, int y) compositeCache.put(k, new ActiveRef(cached, compositeCache, k)); return cached; } - } - + } + + /** This method merges two icons into a new one. The second icon is drawn + * over the first one with its top-left corner at x, y. Icons need not be of the same size. + * The new icon will have a size of max(second icon size + top-left corner, first icon size). + * This method used mostly when second icon contains transparent pixels (e.g. for badging). + * + *

Similar to {@link #mergeImages(Image, Image, int, int)}, but on {@link Icon} instances + * rather than {@link Image} instances. This method is provided as a shortcut to avoid the need + * for conversions in client code. + * + * @param icon1 underlying icon + * @param icon2 second icon + * @param x x position of top-left corner + * @param y y position of top-left corner + * @return new merged icon + * @since 7.36 + */ + public static final Icon mergeIcons(Icon icon1, Icon icon2, int x, int y) { + if (icon1 == null || icon2 == null) { + throw new NullPointerException(); + } + /* Use the Image-based mergeImages implementation rather than just creating a new + MergedIcon instance, to take advantage of the former's cache. Icon instances tend to get + converted back and forth between Icon and Image anyway. */ + return image2Icon(mergeImages(icon2Image(icon1), icon2Image(icon2), x, y)); + } + /** * Converts given image to an icon. * @param image to be converted @@ -384,7 +516,7 @@ methods in this class may be called from any thread, while JLabel's methods and } /** - * Assign tool tip text to given image (creates new or returns cached, original remains unmodified) + * Assign tool tip text to given image (creates new or returns cached, original remains unmodified). * Text can contain HTML tags e.g. "<b>my</b> text" * @param image image to which tool tip should be set * @param text tool tip text @@ -428,7 +560,7 @@ public static final String getImageToolTip(Image image) { } /** - * Add text to tool tip for given image (creates new or returns cached, original remains unmodified) + * Add text to tool tip for given image (creates new or returns cached, original remains unmodified). * Text can contain HTML tags e.g. "<b>my</b> text" * @param text text to add to tool tip * @return Image with attached tool tip @@ -449,7 +581,7 @@ public static final Image addToolTipToImage(Image image, String text) { /** * Creates disabled (color saturation lowered) icon. - * Icon image conversion is performed lazily. + * * @param icon original icon used for conversion * @return less saturated Icon * @since 7.28 @@ -465,6 +597,7 @@ public static Icon createDisabledIcon(Icon icon) { /** * Creates disabled (color saturation lowered) image. + * * @param image original image used for conversion * @return less saturated Image * @since 7.28 @@ -849,7 +982,7 @@ private static void ensureLoaded(Image image) { } } - private static final ToolTipImage doMergeImages(Image image1, Image image2, int x, int y) { + private static ToolTipImage doMergeImages(Image image1, Image image2, int x, int y) { ensureLoaded(image1); ensureLoaded(image2);