diff -r 055826baee46 openide.explorer/src/org/openide/explorer/view/VisualizerNode.java
--- a/openide.explorer/src/org/openide/explorer/view/VisualizerNode.java Fri Jun 13 10:15:48 2008 +0200
+++ b/openide.explorer/src/org/openide/explorer/view/VisualizerNode.java Fri Jun 13 12:59:38 2008 +0200
@@ -56,10 +56,10 @@
import java.util.*;
import javax.swing.Icon;
-import javax.swing.ImageIcon;
import javax.swing.SwingUtilities;
import javax.swing.event.EventListenerList;
import javax.swing.tree.TreeNode;
+import org.openide.util.ImageUtilities;
/** Visual representation of one node. Holds necessary information about nodes
@@ -206,7 +206,14 @@
if (desc == UNKNOWN) {
shortDescription = desc = node.getShortDescription();
}
-
+ if (icon instanceof Image) {
+ String toolTip = ImageUtilities.getImageToolTip((Image) icon);
+ if (toolTip.length() > 0) {
+ StringBuilder str = new StringBuilder(128);
+ str.append("").append(desc).append(" ").append(toolTip).append("");
+ desc = str.toString();
+ }
+ }
return desc;
}
@@ -407,7 +414,7 @@
if (Node.PROP_NAME.equals(name) || Node.PROP_DISPLAY_NAME.equals(name) || isIconChange) {
if (isIconChange) {
//Ditch the cached icon type so the next call to getIcon() will
- //recreate the ImageIcon
+ //recreate the Icon
cachedIconType = -1;
}
@@ -558,7 +565,7 @@
icon = getDefaultIcon();
} else {
- icon = new ImageIcon(image);
+ icon = ImageUtilities.image2Icon(image);
}
}
@@ -577,9 +584,8 @@
/** Loads default icon if not loaded. */
private static Icon getDefaultIcon() {
if (defaultIcon == null) {
- defaultIcon = new ImageIcon(Utilities.loadImage(DEFAULT_ICON));
+ defaultIcon = ImageUtilities.image2Icon(ImageUtilities.loadImage(DEFAULT_ICON));
}
-
return defaultIcon;
}
diff -r 055826baee46 openide.explorer/test/unit/src/org/openide/explorer/view/VisualizerNodeTest.java
--- a/openide.explorer/test/unit/src/org/openide/explorer/view/VisualizerNodeTest.java Fri Jun 13 10:15:48 2008 +0200
+++ b/openide.explorer/test/unit/src/org/openide/explorer/view/VisualizerNodeTest.java Fri Jun 13 12:59:38 2008 +0200
@@ -89,4 +89,16 @@
assertEquals("Index is 1", 1, ta.getIndex(tm));
}
+
+ public void testIconsAreShared() {
+ AbstractNode a1 = new AbstractNode(Children.LEAF);
+ VisualizerNode v1 = VisualizerNode.getVisualizer(null, a1);
+ Icon icon1 = v1.getIcon(false, false);
+
+ AbstractNode a2 = new AbstractNode(Children.LEAF);
+ VisualizerNode v2 = VisualizerNode.getVisualizer(null, a2);
+ Icon icon2 = v2.getIcon(false, false);
+
+ assertSame("Icon instances should be same", icon1, icon2);
+ }
}
diff -r 055826baee46 openide.util/apichanges.xml
--- a/openide.util/apichanges.xml Fri Jun 13 10:15:48 2008 +0200
+++ b/openide.util/apichanges.xml Fri Jun 13 12:59:38 2008 +0200
@@ -49,6 +49,38 @@
Actions API
+
+
+ Image methods were made deprecated in Utilities, replacement is ImageUtilities (with additional methods).
+
+
+
+
+
+
+ Image methods were made deprecated in Utilities. Replacement is
+ ImageUtilities (renamed IconManager). It contains also new
+ methods for image tool tips manipulation:
+ New methods for tool tips manipulation:
+ Image assignToolTipToImage(Image image, String text);
+ String getImageToolTip(Image image);
+ Image addToolTipToImage(Image image, String text);
+
+
+ New method for conversion from Image to Icon:
+ Icon image2Icon(Image image);
+
+
+ Deprecated methods in Utilities:
+ Image icon2Image(Icon icon);
+ Image loadImage(String resourceID);
+ Image loadImage(String resource, boolean localized);
+ Image mergeImages(Image image1, Image image2, int x, int y);
+
+
+
+
+ Mutex made pluggable
diff -r 055826baee46 openide.util/nbproject/project.properties
--- a/openide.util/nbproject/project.properties Fri Jun 13 10:15:48 2008 +0200
+++ b/openide.util/nbproject/project.properties Fri Jun 13 12:59:38 2008 +0200
@@ -41,7 +41,7 @@
javac.source=1.5
module.jar.dir=lib
-spec.version.base=7.13.0
+spec.version.base=7.14.0
# For XMLSerializer, needed for XMLUtil.write to work w/ namespaces under JDK 1.4:
diff -r 055826baee46 openide.util/src/org/openide/util/IconManager.java
--- a/openide.util/src/org/openide/util/IconManager.java Fri Jun 13 10:15:48 2008 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,517 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
- *
- * The contents of this file are subject to the terms of either the GNU
- * General Public License Version 2 only ("GPL") or the Common
- * Development and Distribution License("CDDL") (collectively, the
- * "License"). You may not use this file except in compliance with the
- * License. You can obtain a copy of the License at
- * http://www.netbeans.org/cddl-gplv2.html
- * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
- * specific language governing permissions and limitations under the
- * License. When distributing the software, include this License Header
- * Notice in each file and include the License file at
- * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Sun in the GPL Version 2 section of the License file that
- * accompanied this code. If applicable, add the following below the
- * License Header, with the fields enclosed by brackets [] replaced by
- * your own identifying information:
- * "Portions Copyrighted [year] [name of copyright owner]"
- *
- * Contributor(s):
- *
- * The Original Software is NetBeans. The Initial Developer of the Original
- * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
- * Microsystems, Inc. All Rights Reserved.
- *
- * If you wish your version of this file to be governed by only the CDDL
- * or only the GPL Version 2, indicate your decision by adding
- * "[Contributor] elects to include this software in this distribution
- * under the [CDDL or GPL Version 2] license." If you do not indicate a
- * single choice of license, a recipient has the option to distribute
- * your version of this file under either the CDDL, the GPL Version 2 or
- * to extend the choice of license to its licensees as provided above.
- * However, if you add GPL Version 2 code and therefore, elected the GPL
- * Version 2 license, then the option applies only if the new code is
- * made subject to such option by the copyright holder.
- */
-
-package org.openide.util;
-
-import java.awt.Component;
-import java.awt.HeadlessException;
-import java.awt.Image;
-import java.awt.MediaTracker;
-import java.awt.Toolkit;
-import java.awt.Transparency;
-import java.awt.image.BufferedImage;
-import java.awt.image.ColorModel;
-import java.awt.image.ImageObserver;
-import java.io.IOException;
-import java.lang.ref.SoftReference;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import javax.imageio.ImageIO;
-import javax.imageio.ImageReadParam;
-import javax.imageio.ImageReader;
-import javax.imageio.stream.ImageInputStream;
-
-/** Registers all loaded images into the AbstractNode, so nothing is loaded twice.
-*
-* @author Jaroslav Tulach
-*/
-final class IconManager extends Object {
- /** a value that indicates that the icon does not exists */
- private static final ActiveRef NO_ICON = new ActiveRef(null, null, null);
-
- private static final Map> cache = new HashMap>(128);
- private static final Map> localizedCache = new HashMap>(128);
- private static final Map> compositeCache = new HashMap>(128);
-
- /** Resource paths for which we have had to strip initial slash.
- * @see "#20072"
- */
- private static final Set extraInitialSlashes = new HashSet();
- private static volatile Object currentLoader;
- private static Lookup.Result loaderQuery = null;
- private static boolean noLoaderWarned = false;
- private static final Component component = new Component() {
- };
-
- private static final MediaTracker tracker = new MediaTracker(component);
- private static int mediaTrackerID;
-
- private static ImageReader PNG_READER;
-// private static ImageReader GIF_READER;
-
- private static final Logger ERR = Logger.getLogger(IconManager.class.getName());
-
- static {
- ImageIO.setUseCache(false);
- PNG_READER = ImageIO.getImageReadersByMIMEType("image/png").next();
-// GIF_READER = ImageIO.getImageReadersByMIMEType("image/gif").next();
- }
-
- /**
- * Get the class loader from lookup.
- * Since this is done very frequently, it is wasteful to query lookup each time.
- * Instead, remember the last result and just listen for changes.
- */
- static ClassLoader getLoader() {
- Object is = currentLoader;
- if (is instanceof ClassLoader) {
- return (ClassLoader)is;
- }
-
- currentLoader = Thread.currentThread();
-
- if (loaderQuery == null) {
- loaderQuery = Lookup.getDefault().lookup(new Lookup.Template(ClassLoader.class));
- loaderQuery.addLookupListener(
- new LookupListener() {
- public void resultChanged(LookupEvent ev) {
- ERR.fine("Loader cleared"); // NOI18N
- currentLoader = null;
- }
- }
- );
- }
-
- Iterator it = loaderQuery.allInstances().iterator();
- if (it.hasNext()) {
- ClassLoader toReturn = (ClassLoader) it.next();
- if (currentLoader == Thread.currentThread()) {
- currentLoader = toReturn;
- }
- ERR.fine("Loader computed: " + currentLoader); // NOI18N
- return toReturn;
- } else { if (!noLoaderWarned) {
- noLoaderWarned = true;
- ERR.warning(
- "No ClassLoader instance found in " + Lookup.getDefault() // NOI18N
- );
- }
- return null;
- }
- }
-
- static Image getIcon(String resource, boolean localized) {
- if (localized) {
- synchronized (localizedCache) {
- ActiveRef ref = localizedCache.get(resource);
- Image img = null;
-
- // no icon for this name (already tested)
- if (ref == NO_ICON) {
- return null;
- }
-
- if (ref != null) {
- // then it is SoftRefrence
- img = ref.get();
- }
-
- // icon found
- if (img != null) {
- return img;
- }
-
- // find localized or base image
- ClassLoader loader = getLoader();
-
- // we'll keep the String probably for long time, optimize it
- resource = new String(resource).intern(); // NOPMD
-
- String base;
- String ext;
- int idx = resource.lastIndexOf('.');
-
- if ((idx != -1) && (idx > resource.lastIndexOf('/'))) {
- base = resource.substring(0, idx);
- ext = resource.substring(idx);
- } else {
- base = resource;
- ext = ""; // NOI18N
- }
-
- // #31008. [PENDING] remove in case package cache is precomputed
- java.net.URL baseurl = (loader != null) ? loader.getResource(resource) // NOPMD
- : IconManager.class.getClassLoader().getResource(resource);
- Iterator it = NbBundle.getLocalizingSuffixes();
-
- while (it.hasNext()) {
- String suffix = it.next();
- Image i;
-
- if (suffix.length() == 0) {
- i = getIcon(resource, loader, false);
- } else {
- i = getIcon(base + suffix + ext, loader, true);
- }
-
- if (i != null) {
- localizedCache.put(resource, new ActiveRef(i, localizedCache, resource));
-
- return i;
- }
- }
-
- localizedCache.put(resource, NO_ICON);
-
- return null;
- }
- } else {
- return getIcon(resource, getLoader(), false);
- }
- }
-
- /** Finds image for given resource.
- * @param name name of the resource
- * @param loader classloader to use for locating it, or null to use classpath
- * @param localizedQuery whether the name contains some localization suffix
- * and is not optimized/interned
- */
- private static Image getIcon(String name, ClassLoader loader, boolean localizedQuery) {
- ActiveRef ref = cache.get(name);
- Image img = null;
-
- // no icon for this name (already tested)
- if (ref == NO_ICON) {
- return null;
- }
-
- if (ref != null) {
- img = ref.get();
- }
-
- // icon found
- if (img != null) {
- return img;
- }
-
- synchronized (cache) {
- // again under the lock
- ref = cache.get(name);
-
- // no icon for this name (already tested)
- if (ref == NO_ICON) {
- return null;
- }
-
- if (ref != null) {
- // then it is SoftRefrence
- img = ref.get();
- }
-
- if (img != null) {
- // cannot be NO_ICON, since it never disappears from the map.
- return img;
- }
-
- // path for bug in classloader
- String n;
- boolean warn;
-
- if (name.startsWith("/")) { // NOI18N
- warn = true;
- n = name.substring(1);
- } else {
- warn = false;
- n = name;
- }
-
- // we have to load it
- java.net.URL url = (loader != null) ? loader.getResource(n)
- : IconManager.class.getClassLoader().getResource(n);
-
-// img = (url == null) ? null : Toolkit.getDefaultToolkit().createImage(url);
- Image result = null;
- try {
- if (url != null) {
- if (name.endsWith(".png")) {
- ImageInputStream stream = ImageIO.createImageInputStream(url.openStream());
- ImageReadParam param = PNG_READER.getDefaultReadParam();
- try {
- PNG_READER.setInput(stream, true, true);
- result = PNG_READER.read(0, param);
- }
- catch (IOException ioe1) {
- ERR.log(Level.INFO, "Image "+name+" is not PNG", ioe1);
- }
- stream.close();
- }
- /*
- else if (name.endsWith(".gif")) {
- ImageInputStream stream = ImageIO.createImageInputStream(url.openStream());
- ImageReadParam param = GIF_READER.getDefaultReadParam();
- try {
- GIF_READER.setInput(stream, true, true);
- result = GIF_READER.read(0, param);
- }
- catch (IOException ioe1) {
- ERR.log(Level.INFO, "Image "+name+" is not GIF", ioe1);
- }
- stream.close();
- }
- */
-
- if (result == null) {
- result = ImageIO.read(url);
- }
- }
- } catch (IOException ioe) {
- ERR.log(Level.WARNING, "Cannot load " + name + " image", ioe);
- }
-
- if (result != null) {
- if (warn && extraInitialSlashes.add(name)) {
- ERR.warning(
- "Initial slashes in Utilities.loadImage deprecated (cf. #20072): " +
- name
- ); // NOI18N
- }
-
-// Image img2 = toBufferedImage(result);
-
- ERR.log(Level.FINE,
- "loading icon {0} = {1}", new Object[] {n, result});
- name = new String(name).intern(); // NOPMD
-
- cache.put(name, new ActiveRef(result, cache, name));
-
- return result;
- } else { // no icon found
-
- if (!localizedQuery) {
- cache.put(name, NO_ICON);
- }
-
- return null;
- }
- }
- }
-
- /**
- * Method that attempts to find the merged image in the cache first, then
- * creates the image if it was not found.
- */
- static final Image mergeImages(Image im1, Image im2, int x, int y) {
- CompositeImageKey k = new CompositeImageKey(im1, im2, x, y);
- Image cached;
-
- synchronized (compositeCache) {
- ActiveRef r = compositeCache.get(k);
-
- if (r != null) {
- cached = r.get();
-
- if (cached != null) {
- return cached;
- }
- }
-
- cached = doMergeImages(im1, im2, x, y);
- compositeCache.put(k, new ActiveRef(cached, compositeCache, k));
-
- return cached;
- }
- }
-
- /** The method creates a BufferedImage which represents the same Image as the
- * parameter but consumes less memory.
- */
- static final Image toBufferedImage(Image img) {
- // load the image
- new javax.swing.ImageIcon(img, "");
-
- if (img.getHeight(null)*img.getWidth(null) > 24*24) {
- return img;
- }
- java.awt.image.BufferedImage rep = createBufferedImage(img.getWidth(null), img.getHeight(null));
- java.awt.Graphics g = rep.createGraphics();
- g.drawImage(img, 0, 0, null);
- g.dispose();
- img.flush();
-
- return rep;
- }
-
- private static void ensureLoaded(Image image) {
- if (
- (Toolkit.getDefaultToolkit().checkImage(image, -1, -1, null) &
- (ImageObserver.ALLBITS | ImageObserver.FRAMEBITS)) != 0
- ) {
- return;
- }
-
- synchronized (tracker) {
- int id = ++mediaTrackerID;
-
- tracker.addImage(image, id);
-
- try {
- tracker.waitForID(id, 0);
- } catch (InterruptedException e) {
- System.out.println("INTERRUPTED while loading Image");
- }
-
- assert (tracker.statusID(id, false) == MediaTracker.COMPLETE) : "Image loaded";
- tracker.removeImage(image, id);
- }
- }
-
- private static final Image doMergeImages(Image image1, Image image2, int x, int y) {
- ensureLoaded(image1);
- ensureLoaded(image2);
-
- int w = Math.max(image1.getWidth(null), x + image2.getWidth(null));
- int h = Math.max(image1.getHeight(null), y + image2.getHeight(null));
- boolean bitmask = (image1 instanceof Transparency) && ((Transparency)image1).getTransparency() != Transparency.TRANSLUCENT
- && (image2 instanceof Transparency) && ((Transparency)image2).getTransparency() != Transparency.TRANSLUCENT;
-
- ColorModel model = colorModel(bitmask? Transparency.BITMASK: Transparency.TRANSLUCENT);
- java.awt.image.BufferedImage buffImage = new java.awt.image.BufferedImage(
- model, model.createCompatibleWritableRaster(w, h), model.isAlphaPremultiplied(), null
- );
-
- java.awt.Graphics g = buffImage.createGraphics();
- g.drawImage(image1, 0, 0, null);
- g.drawImage(image2, x, y, null);
- g.dispose();
-
- return buffImage;
- }
-
- /** Creates BufferedImage with Transparency.TRANSLUCENT */
- static final java.awt.image.BufferedImage createBufferedImage(int width, int height) {
- if (Utilities.isMac()) {
- return new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE);
- }
-
- ColorModel model = colorModel(java.awt.Transparency.TRANSLUCENT);
- java.awt.image.BufferedImage buffImage = new java.awt.image.BufferedImage(
- model, model.createCompatibleWritableRaster(width, height), model.isAlphaPremultiplied(), null
- );
-
- return buffImage;
- }
-
- static private ColorModel colorModel(int transparency) {
- ColorModel model;
- try {
- model = java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment()
- .getDefaultScreenDevice().getDefaultConfiguration()
- .getColorModel(transparency);
- }
- catch(HeadlessException he) {
- model = ColorModel.getRGBdefault();
- }
-
- return model;
- }
-
- /**
- * Key used for composite images -- it holds image identities
- */
- private static class CompositeImageKey {
- Image baseImage;
- Image overlayImage;
- int x;
- int y;
-
- CompositeImageKey(Image base, Image overlay, int x, int y) {
- this.x = x;
- this.y = y;
- this.baseImage = base;
- this.overlayImage = overlay;
- }
-
- public boolean equals(Object other) {
- if (!(other instanceof CompositeImageKey)) {
- return false;
- }
-
- CompositeImageKey k = (CompositeImageKey) other;
-
- return (x == k.x) && (y == k.y) && (baseImage == k.baseImage) && (overlayImage == k.overlayImage);
- }
-
- public int hashCode() {
- int hash = ((x << 3) ^ y) << 4;
- hash = hash ^ baseImage.hashCode() ^ overlayImage.hashCode();
-
- return hash;
- }
-
- public String toString() {
- return "Composite key for " + baseImage + " + " + overlayImage + " at [" + x + ", " + y + "]"; // NOI18N
- }
- }
-
- /** Cleaning reference. */
- private static final class ActiveRef extends SoftReference implements Runnable {
- private Map> holder;
- private T key;
-
- public ActiveRef(Image o, Map> holder, T key) {
- super(o, Utilities.activeReferenceQueue());
- this.holder = holder;
- this.key = key;
- }
-
- public void run() {
- synchronized (holder) {
- holder.remove(key);
- }
- }
- }
- // end of ActiveRef
-}
diff -r 055826baee46 openide.util/src/org/openide/util/ImageUtilities.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/openide.util/src/org/openide/util/ImageUtilities.java Fri Jun 13 12:59:38 2008 +0200
@@ -0,0 +1,738 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
+ * Microsystems, Inc. All Rights Reserved.
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ */
+
+package org.openide.util;
+
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.HeadlessException;
+import java.awt.Image;
+import java.awt.MediaTracker;
+import java.awt.Toolkit;
+import java.awt.Transparency;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.ImageObserver;
+import java.awt.image.IndexColorModel;
+import java.awt.image.WritableRaster;
+import java.io.IOException;
+import java.lang.ref.SoftReference;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.imageio.ImageIO;
+import javax.imageio.ImageReadParam;
+import javax.imageio.ImageReader;
+import javax.imageio.stream.ImageInputStream;
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+import javax.swing.JLabel;
+
+/**
+ * Useful static methods for manipulation with images/icons, results are cached.
+ *
+ * @author Jaroslav Tulach
+ * @since 7.14
+ */
+public final class ImageUtilities {
+ /** separator for individual parts of tool tip text */
+ static final String TOOLTIP_SEPAR = " "; // NOI18N
+ /** a value that indicates that the icon does not exists */
+ private static final ActiveRef NO_ICON = new ActiveRef(null, null, null);
+
+ private static final Map> cache = new HashMap>(128);
+ private static final Map> localizedCache = new HashMap>(128);
+ private static final Map> compositeCache = new HashMap>(128);
+ private static final Map> imageToolTipCache = new HashMap>(128);
+
+ /** Resource paths for which we have had to strip initial slash.
+ * @see "#20072"
+ */
+ private static final Set extraInitialSlashes = new HashSet();
+ private static volatile Object currentLoader;
+ private static Lookup.Result loaderQuery = null;
+ private static boolean noLoaderWarned = false;
+ private static final Component component = new Component() {
+ };
+
+ private static final MediaTracker tracker = new MediaTracker(component);
+ private static int mediaTrackerID;
+
+ private static ImageReader PNG_READER;
+// private static ImageReader GIF_READER;
+
+ private static final Logger ERR = Logger.getLogger(ImageUtilities.class.getName());
+
+ static {
+ ImageIO.setUseCache(false);
+ PNG_READER = ImageIO.getImageReadersByMIMEType("image/png").next();
+// GIF_READER = ImageIO.getImageReadersByMIMEType("image/gif").next();
+ }
+
+ /**
+ * Loads an image from the specified resource ID. The image is loaded using the "system" classloader registered in
+ * Lookup.
+ * @param resourceID resource path of the icon (no initial slash)
+ * @return icon's Image, or null, if the icon cannot be loaded.
+ */
+ public static final Image loadImage(String resourceID) {
+ return getIcon(resourceID, false);
+ }
+
+ /**
+ * Loads an image based on 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.
+ *
+ */
+ public static final Image loadImage(String resource, boolean localized) {
+ return getIcon(resource, localized);
+ }
+
+ /** This method merges two images into the new 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.
+ * @param image1 underlying image
+ * @param image2 second image
+ * @param x x position of top-left corner
+ * @param y y position of top-left corner
+ * @return new merged image
+ */
+ public static final Image mergeImages(Image image1, Image image2, int x, int y) {
+ if (image1 == null || image2 == null) {
+ throw new NullPointerException();
+ }
+
+ CompositeImageKey k = new CompositeImageKey(image1, image2, x, y);
+ Image cached;
+
+ synchronized (compositeCache) {
+ ActiveRef r = compositeCache.get(k);
+ if (r != null) {
+ cached = r.get();
+ if (cached != null) {
+ return cached;
+ }
+ }
+ cached = doMergeImages(image1, image2, x, y);
+ compositeCache.put(k, new ActiveRef(cached, compositeCache, k));
+ return cached;
+ }
+ }
+
+ /**
+ * Converts given image to a {@link javax.swing.Icon}.
+ * @param image {@link java.awt.Image} to be converted.
+ * @return icon corresponding {@link javax.swing.Icon}
+ */
+ public static final Icon image2Icon(Image image) {
+ if (image instanceof ToolTipImage) {
+ return (Icon) image;
+ } else {
+ return new ImageIcon(image);
+ }
+ }
+
+ /**
+ * Converts given icon to a {@link java.awt.Image}.
+ *
+ * @param icon {@link javax.swing.Icon} to be converted.
+ */
+ public static final Image icon2Image(Icon icon) {
+ if (icon instanceof ToolTipImage) {
+ return (Image) icon;
+ } else {
+ ToolTipImage image = new ToolTipImage("", icon.getIconWidth(), icon.getIconHeight(), BufferedImage.TYPE_INT_ARGB);
+ Graphics g = image.getGraphics();
+ icon.paintIcon(new JLabel(), g, 0, 0);
+ g.dispose();
+ return image;
+ }
+ }
+
+ /**
+ * 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
+ * @return Image with attached tool tip
+ */
+ public static final Image assignToolTipToImage(Image image, String text) {
+ ToolTipImageKey key = new ToolTipImageKey(image, text);
+ Image cached;
+ synchronized (imageToolTipCache) {
+ ActiveRef r = imageToolTipCache.get(key);
+ if (r != null) {
+ cached = r.get();
+ if (cached != null) {
+ return cached;
+ }
+ }
+ cached = ToolTipImage.createNew(text, image);
+ imageToolTipCache.put(key, new ActiveRef(cached, imageToolTipCache, key));
+ return cached;
+ }
+ }
+
+ /**
+ * Get tool tip text for given image
+ * @param image image which is asked for tool tip text
+ * @return String containing attached tool tip text
+ */
+ public static final String getImageToolTip(Image image) {
+ if (image instanceof ToolTipImage) {
+ return ((ToolTipImage) image).toolTipText;
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * 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
+ */
+ public static final Image addToolTipToImage(Image image, String text) {
+ if (image instanceof ToolTipImage) {
+ ToolTipImage tti = (ToolTipImage) image;
+ StringBuilder str = new StringBuilder(tti.toolTipText);
+ if (str.length() > 0 && text.length() > 0) {
+ str.append(TOOLTIP_SEPAR);
+ }
+ str.append(text);
+ return assignToolTipToImage(image, str.toString());
+ } else {
+ return assignToolTipToImage(image, text);
+ }
+ }
+
+ /**
+ * Get the class loader from lookup.
+ * Since this is done very frequently, it is wasteful to query lookup each time.
+ * Instead, remember the last result and just listen for changes.
+ */
+ static ClassLoader getLoader() {
+ Object is = currentLoader;
+ if (is instanceof ClassLoader) {
+ return (ClassLoader)is;
+ }
+
+ currentLoader = Thread.currentThread();
+
+ if (loaderQuery == null) {
+ loaderQuery = Lookup.getDefault().lookup(new Lookup.Template(ClassLoader.class));
+ loaderQuery.addLookupListener(
+ new LookupListener() {
+ public void resultChanged(LookupEvent ev) {
+ ERR.fine("Loader cleared"); // NOI18N
+ currentLoader = null;
+ }
+ }
+ );
+ }
+
+ Iterator it = loaderQuery.allInstances().iterator();
+ if (it.hasNext()) {
+ ClassLoader toReturn = (ClassLoader) it.next();
+ if (currentLoader == Thread.currentThread()) {
+ currentLoader = toReturn;
+ }
+ ERR.fine("Loader computed: " + currentLoader); // NOI18N
+ return toReturn;
+ } else { if (!noLoaderWarned) {
+ noLoaderWarned = true;
+ ERR.warning(
+ "No ClassLoader instance found in " + Lookup.getDefault() // NOI18N
+ );
+ }
+ return null;
+ }
+ }
+
+ static Image getIcon(String resource, boolean localized) {
+ if (localized) {
+ synchronized (localizedCache) {
+ ActiveRef ref = localizedCache.get(resource);
+ Image img = null;
+
+ // no icon for this name (already tested)
+ if (ref == NO_ICON) {
+ return null;
+ }
+
+ if (ref != null) {
+ // then it is SoftRefrence
+ img = ref.get();
+ }
+
+ // icon found
+ if (img != null) {
+ return img;
+ }
+
+ // find localized or base image
+ ClassLoader loader = getLoader();
+
+ // we'll keep the String probably for long time, optimize it
+ resource = new String(resource).intern(); // NOPMD
+
+ String base;
+ String ext;
+ int idx = resource.lastIndexOf('.');
+
+ if ((idx != -1) && (idx > resource.lastIndexOf('/'))) {
+ base = resource.substring(0, idx);
+ ext = resource.substring(idx);
+ } else {
+ base = resource;
+ ext = ""; // NOI18N
+ }
+
+ // #31008. [PENDING] remove in case package cache is precomputed
+ java.net.URL baseurl = (loader != null) ? loader.getResource(resource) // NOPMD
+ : ImageUtilities.class.getClassLoader().getResource(resource);
+ Iterator it = NbBundle.getLocalizingSuffixes();
+
+ while (it.hasNext()) {
+ String suffix = it.next();
+ Image i;
+
+ if (suffix.length() == 0) {
+ i = getIcon(resource, loader, false);
+ } else {
+ i = getIcon(base + suffix + ext, loader, true);
+ }
+
+ if (i != null) {
+ localizedCache.put(resource, new ActiveRef(i, localizedCache, resource));
+ return i;
+ }
+ }
+ localizedCache.put(resource, NO_ICON);
+ return null;
+ }
+ } else {
+ return getIcon(resource, getLoader(), false);
+ }
+ }
+
+ /** Finds image for given resource.
+ * @param name name of the resource
+ * @param loader classloader to use for locating it, or null to use classpath
+ * @param localizedQuery whether the name contains some localization suffix
+ * and is not optimized/interned
+ */
+ private static Image getIcon(String name, ClassLoader loader, boolean localizedQuery) {
+ ActiveRef ref = cache.get(name);
+ Image img = null;
+
+ // no icon for this name (already tested)
+ if (ref == NO_ICON) {
+ return null;
+ }
+
+ if (ref != null) {
+ img = ref.get();
+ }
+
+ // icon found
+ if (img != null) {
+ return img;
+ }
+
+ synchronized (cache) {
+ // again under the lock
+ ref = cache.get(name);
+
+ // no icon for this name (already tested)
+ if (ref == NO_ICON) {
+ return null;
+ }
+
+ if (ref != null) {
+ // then it is SoftRefrence
+ img = ref.get();
+ }
+
+ if (img != null) {
+ // cannot be NO_ICON, since it never disappears from the map.
+ return img;
+ }
+
+ // path for bug in classloader
+ String n;
+ boolean warn;
+
+ if (name.startsWith("/")) { // NOI18N
+ warn = true;
+ n = name.substring(1);
+ } else {
+ warn = false;
+ n = name;
+ }
+
+ // we have to load it
+ java.net.URL url = (loader != null) ? loader.getResource(n)
+ : ImageUtilities.class.getClassLoader().getResource(n);
+
+// img = (url == null) ? null : Toolkit.getDefaultToolkit().createImage(url);
+ Image result = null;
+ try {
+ if (url != null) {
+ if (name.endsWith(".png")) {
+ ImageInputStream stream = ImageIO.createImageInputStream(url.openStream());
+ ImageReadParam param = PNG_READER.getDefaultReadParam();
+ try {
+ PNG_READER.setInput(stream, true, true);
+ result = PNG_READER.read(0, param);
+ }
+ catch (IOException ioe1) {
+ ERR.log(Level.INFO, "Image "+name+" is not PNG", ioe1);
+ }
+ stream.close();
+ }
+ /*
+ else if (name.endsWith(".gif")) {
+ ImageInputStream stream = ImageIO.createImageInputStream(url.openStream());
+ ImageReadParam param = GIF_READER.getDefaultReadParam();
+ try {
+ GIF_READER.setInput(stream, true, true);
+ result = GIF_READER.read(0, param);
+ }
+ catch (IOException ioe1) {
+ ERR.log(Level.INFO, "Image "+name+" is not GIF", ioe1);
+ }
+ stream.close();
+ }
+ */
+
+ if (result == null) {
+ result = ImageIO.read(url);
+ }
+ }
+ } catch (IOException ioe) {
+ ERR.log(Level.WARNING, "Cannot load " + name + " image", ioe);
+ }
+
+ if (result != null) {
+ if (warn && extraInitialSlashes.add(name)) {
+ ERR.warning(
+ "Initial slashes in Utilities.loadImage deprecated (cf. #20072): " +
+ name
+ ); // NOI18N
+ }
+
+// Image img2 = toBufferedImage(result);
+
+ ERR.log(Level.FINE, "loading icon {0} = {1}", new Object[] {n, result});
+ name = new String(name).intern(); // NOPMD
+ result = ToolTipImage.createNew("", result);
+ cache.put(name, new ActiveRef(result, cache, name));
+ return result;
+ } else { // no icon found
+ if (!localizedQuery) {
+ cache.put(name, NO_ICON);
+ }
+ return null;
+ }
+ }
+ }
+
+ /** The method creates a BufferedImage which represents the same Image as the
+ * parameter but consumes less memory.
+ */
+ static final Image toBufferedImage(Image img) {
+ // load the image
+ new javax.swing.ImageIcon(img, "");
+
+ if (img.getHeight(null)*img.getWidth(null) > 24*24) {
+ return img;
+ }
+ java.awt.image.BufferedImage rep = createBufferedImage(img.getWidth(null), img.getHeight(null));
+ java.awt.Graphics g = rep.createGraphics();
+ g.drawImage(img, 0, 0, null);
+ g.dispose();
+ img.flush();
+
+ return rep;
+ }
+
+ private static void ensureLoaded(Image image) {
+ if (
+ (Toolkit.getDefaultToolkit().checkImage(image, -1, -1, null) &
+ (ImageObserver.ALLBITS | ImageObserver.FRAMEBITS)) != 0
+ ) {
+ return;
+ }
+
+ synchronized (tracker) {
+ int id = ++mediaTrackerID;
+ tracker.addImage(image, id);
+
+ try {
+ tracker.waitForID(id, 0);
+ } catch (InterruptedException e) {
+ System.out.println("INTERRUPTED while loading Image");
+ }
+
+ assert (tracker.statusID(id, false) == MediaTracker.COMPLETE) : "Image loaded";
+ tracker.removeImage(image, id);
+ }
+ }
+
+ private static final Image doMergeImages(Image image1, Image image2, int x, int y) {
+ ensureLoaded(image1);
+ ensureLoaded(image2);
+
+ int w = Math.max(image1.getWidth(null), x + image2.getWidth(null));
+ int h = Math.max(image1.getHeight(null), y + image2.getHeight(null));
+ boolean bitmask = (image1 instanceof Transparency) && ((Transparency)image1).getTransparency() != Transparency.TRANSLUCENT
+ && (image2 instanceof Transparency) && ((Transparency)image2).getTransparency() != Transparency.TRANSLUCENT;
+
+ StringBuilder str = new StringBuilder(image1 instanceof ToolTipImage ? ((ToolTipImage)image1).toolTipText : "");
+ if (image2 instanceof ToolTipImage) {
+ String toolTip = ((ToolTipImage)image2).toolTipText;
+ if (str.length() > 0 && toolTip.length() > 0) {
+ str.append(TOOLTIP_SEPAR);
+ }
+ str.append(toolTip);
+ }
+
+ ColorModel model = colorModel(bitmask? Transparency.BITMASK: Transparency.TRANSLUCENT);
+ ToolTipImage buffImage = new ToolTipImage(str.toString(),
+ model, model.createCompatibleWritableRaster(w, h), model.isAlphaPremultiplied(), null
+ );
+
+ java.awt.Graphics g = buffImage.createGraphics();
+ g.drawImage(image1, 0, 0, null);
+ g.drawImage(image2, x, y, null);
+ g.dispose();
+
+ return buffImage;
+ }
+
+ /** Creates BufferedImage with Transparency.TRANSLUCENT */
+ static final java.awt.image.BufferedImage createBufferedImage(int width, int height) {
+ if (Utilities.isMac()) {
+ return new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE);
+ }
+
+ ColorModel model = colorModel(java.awt.Transparency.TRANSLUCENT);
+ java.awt.image.BufferedImage buffImage = new java.awt.image.BufferedImage(
+ model, model.createCompatibleWritableRaster(width, height), model.isAlphaPremultiplied(), null
+ );
+
+ return buffImage;
+ }
+
+ static private ColorModel colorModel(int transparency) {
+ ColorModel model;
+ try {
+ model = java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment()
+ .getDefaultScreenDevice().getDefaultConfiguration()
+ .getColorModel(transparency);
+ }
+ catch(HeadlessException he) {
+ model = ColorModel.getRGBdefault();
+ }
+ return model;
+ }
+
+ /**
+ * Key used for composite images -- it holds image identities
+ */
+ private static class CompositeImageKey {
+ Image baseImage;
+ Image overlayImage;
+ int x;
+ int y;
+
+ CompositeImageKey(Image base, Image overlay, int x, int y) {
+ this.x = x;
+ this.y = y;
+ this.baseImage = base;
+ this.overlayImage = overlay;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof CompositeImageKey)) {
+ return false;
+ }
+
+ CompositeImageKey k = (CompositeImageKey) other;
+
+ return (x == k.x) && (y == k.y) && (baseImage == k.baseImage) && (overlayImage == k.overlayImage);
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = ((x << 3) ^ y) << 4;
+ hash = hash ^ baseImage.hashCode() ^ overlayImage.hashCode();
+
+ return hash;
+ }
+
+ @Override
+ public String toString() {
+ return "Composite key for " + baseImage + " + " + overlayImage + " at [" + x + ", " + y + "]"; // NOI18N
+ }
+ }
+
+ /**
+ * Key used for ToolTippedImage
+ */
+ private static class ToolTipImageKey {
+ Image image;
+ String str;
+
+ ToolTipImageKey(Image image, String str) {
+ this.image = image;
+ this.str = str;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof ToolTipImageKey)) {
+ return false;
+ }
+ ToolTipImageKey k = (ToolTipImageKey) other;
+ return (str.equals(k.str)) && (image == k.image);
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = image.hashCode() ^ str.hashCode();
+ return hash;
+ }
+
+ @Override
+ public String toString() {
+ return "ImageStringKey for " + image + " + " + str; // NOI18N
+ }
+ }
+
+ /** Cleaning reference. */
+ private static final class ActiveRef extends SoftReference implements Runnable {
+ private Map> holder;
+ private T key;
+
+ public ActiveRef(Image o, Map> holder, T key) {
+ super(o, Utilities.activeReferenceQueue());
+ this.holder = holder;
+ this.key = key;
+ }
+
+ public void run() {
+ synchronized (holder) {
+ holder.remove(key);
+ }
+ }
+ }
+ // end of ActiveRef
+
+ /**
+ * Image with tool tip text (for icons with badges)
+ */
+ private static class ToolTipImage extends BufferedImage implements Icon {
+ final String toolTipText;
+
+ public static ToolTipImage createNew(String toolTipText, Image image) {
+ ImageUtilities.ensureLoaded(image);
+ boolean bitmask = (image instanceof Transparency) && ((Transparency) image).getTransparency() != Transparency.TRANSLUCENT;
+ ColorModel model = colorModel(bitmask ? Transparency.BITMASK : Transparency.TRANSLUCENT);
+ int w = image.getWidth(null);
+ int h = image.getHeight(null);
+ ToolTipImage newImage = new ToolTipImage(toolTipText, model, model.createCompatibleWritableRaster(w, h), model.isAlphaPremultiplied(), null);
+
+ java.awt.Graphics g = newImage.createGraphics();
+ g.drawImage(image, 0, 0, null);
+ g.dispose();
+ return newImage;
+ }
+
+ public ToolTipImage(String toolTipText, ColorModel cm, WritableRaster raster, boolean isRasterPremultiplied, Hashtable, ?> properties) {
+ super(cm, raster, isRasterPremultiplied, properties);
+ this.toolTipText = toolTipText;
+ }
+
+ public ToolTipImage(String toolTipText, int width, int height, int imageType, IndexColorModel cm) {
+ super(width, height, imageType, cm);
+ this.toolTipText = toolTipText;
+ }
+
+ public ToolTipImage(String toolTipText, int width, int height, int imageType) {
+ super(width, height, imageType);
+ this.toolTipText = toolTipText;
+ }
+
+ public ToolTipImage(String toolTipText, BufferedImage image) {
+ super(image.getWidth(), image.getHeight(), image.getType());
+ this.toolTipText = toolTipText;
+ }
+
+
+ public int getIconHeight() {
+ return super.getHeight();
+ }
+
+ public int getIconWidth() {
+ return super.getWidth();
+ }
+
+ public void paintIcon(Component c, Graphics g, int x, int y) {
+ g.drawImage(this, x, y, null);
+ }
+ }
+}
diff -r 055826baee46 openide.util/src/org/openide/util/Utilities.java
--- a/openide.util/src/org/openide/util/Utilities.java Fri Jun 13 10:15:48 2008 +0200
+++ b/openide.util/src/org/openide/util/Utilities.java Fri Jun 13 12:59:38 2008 +0200
@@ -48,7 +48,6 @@
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.Frame;
-import java.awt.Graphics;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
@@ -61,7 +60,6 @@
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
-import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
@@ -99,8 +97,6 @@
import java.util.logging.Logger;
import javax.swing.Action;
import javax.swing.Icon;
-import javax.swing.ImageIcon;
-import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JSeparator;
@@ -2588,33 +2584,28 @@
* 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).
- * If both images are null, it makes default transparent 16x16 image.
* @param image1 underlying image
* @param image2 second image
* @param x x position of top-left corner
* @param y y position of top-left corner
* @return new merged image
+ * @deprecated Use ImageUtilities.mergeImages().
*/
+ @Deprecated
public static final Image mergeImages(Image image1, Image image2, int x, int y) {
- if (image1 == null) {
- throw new NullPointerException();
- }
-
- if (image2 == null) {
- throw new NullPointerException();
- }
-
- return IconManager.mergeImages(image1, image2, x, y);
+ return ImageUtilities.mergeImages(image1, image2, x, y);
}
-
+
/**
* Loads an image from the specified resource ID. The image is loaded using the "system" classloader registered in
* Lookup.
* @param resourceID resource path of the icon (no initial slash)
* @return icon's Image, or null, if the icon cannot be loaded.
+ * @deprecated Use ImageUtilities.loadImage().
*/
+ @Deprecated
public static final Image loadImage(String resourceID) {
- return IconManager.getIcon(resourceID, false);
+ return ImageUtilities.loadImage(resourceID);
}
/**
@@ -2622,17 +2613,11 @@
*
* @param icon {@link javax.swing.Icon} to be converted.
* @since 7.3
+ * @deprecated Use ImageUtilities.iconToImage().
*/
+ @Deprecated
public static final Image icon2Image(Icon icon) {
- if (icon instanceof ImageIcon) {
- return ((ImageIcon) icon).getImage();
- } else {
- BufferedImage bImage = new BufferedImage(icon.getIconWidth(), icon.getIconHeight(), BufferedImage.TYPE_INT_ARGB);
- Graphics g = bImage.getGraphics();
- icon.paintIcon(new JLabel(), g, 0, 0);
- g.dispose();
- return bImage;
- }
+ return ImageUtilities.icon2Image(icon);
}
/** Builds a popup menu from actions for provided context specified by
@@ -2796,9 +2781,11 @@
*
Caching of loaded images can be used internally to improve performance.
*
* @since 3.24
+ * @deprecated Use ImageUtilities.loadImage().
*/
+ @Deprecated
public static final Image loadImage(String resource, boolean localized) {
- return IconManager.getIcon(resource, localized);
+ return ImageUtilities.loadImage(resource, localized);
}
/**
@@ -2865,7 +2852,7 @@
}
// need to resize the icon
- Image empty = IconManager.createBufferedImage(d.width, d.height);
+ Image empty = ImageUtilities.createBufferedImage(d.width, d.height);
i = Utilities.mergeImages(icon, empty, 0, 0);
}
@@ -3038,14 +3025,17 @@
this.deprecated = deprecated;
}
+ @Override
public Reference