1 19 20 package org.openide.util; 21 22 import java.awt.Component ; 23 import java.awt.HeadlessException ; 24 import java.awt.Image ; 25 import java.awt.MediaTracker ; 26 import java.awt.Toolkit ; 27 import java.awt.Transparency ; 28 import java.awt.image.BufferedImage ; 29 import java.awt.image.ColorModel ; 30 import java.awt.image.ImageObserver ; 31 import java.lang.ref.SoftReference ; 32 import java.util.HashMap ; 33 import java.util.HashSet ; 34 import java.util.Iterator ; 35 import java.util.Map ; 36 import java.util.Set ; 37 import java.util.logging.Logger ; 38 39 43 final class IconManager extends Object { 44 45 private static final ActiveRef<String > NO_ICON = new ActiveRef<String >(null, null, null); 46 47 private static final Map <String ,ActiveRef<String >> cache = new HashMap <String ,ActiveRef<String >>(128); 48 private static final Map <String ,ActiveRef<String >> localizedCache = new HashMap <String ,ActiveRef<String >>(128); 49 private static final Map <CompositeImageKey,ActiveRef<CompositeImageKey>> compositeCache = new HashMap <CompositeImageKey,ActiveRef<CompositeImageKey>>(128); 50 51 54 private static final Set <String > extraInitialSlashes = new HashSet <String >(); 55 private static volatile Object currentLoader; 56 private static Lookup.Result<ClassLoader > loaderQuery = null; 57 private static boolean noLoaderWarned = false; 58 private static final Component component = new Component () { 59 }; 60 61 private static final MediaTracker tracker = new MediaTracker (component); 62 private static int mediaTrackerID; 63 64 private static final Logger ERR = Logger.getLogger(IconManager.class.getName()); 65 66 71 static ClassLoader getLoader() { 72 Object is = currentLoader; 73 if (is instanceof ClassLoader ) { 74 return (ClassLoader )is; 75 } 76 77 currentLoader = Thread.currentThread(); 78 79 if (loaderQuery == null) { 80 loaderQuery = Lookup.getDefault().lookup(new Lookup.Template<ClassLoader >(ClassLoader .class)); 81 loaderQuery.addLookupListener( 82 new LookupListener() { 83 public void resultChanged(LookupEvent ev) { 84 ERR.fine("Loader cleared"); currentLoader = null; 86 } 87 } 88 ); 89 } 90 91 Iterator it = loaderQuery.allInstances().iterator(); 92 if (it.hasNext()) { 93 ClassLoader toReturn = (ClassLoader ) it.next(); 94 if (currentLoader == Thread.currentThread()) { 95 currentLoader = toReturn; 96 } 97 ERR.fine("Loader computed: " + currentLoader); return toReturn; 99 } else { if (!noLoaderWarned) { 100 noLoaderWarned = true; 101 ERR.warning( 102 "No ClassLoader instance found in " + Lookup.getDefault() ); 104 } 105 return null; 106 } 107 } 108 109 static Image getIcon(String resource, boolean localized) { 110 if (localized) { 111 synchronized (localizedCache) { 112 ActiveRef<String > ref = localizedCache.get(resource); 113 Image img = null; 114 115 if (ref == NO_ICON) { 117 return null; 118 } 119 120 if (ref != null) { 121 img = ref.get(); 123 } 124 125 if (img != null) { 127 return img; 128 } 129 130 ClassLoader loader = getLoader(); 132 133 resource = new String (resource).intern(); 136 String base; 137 String ext; 138 int idx = resource.lastIndexOf('.'); 139 140 if ((idx != -1) && (idx > resource.lastIndexOf('/'))) { 141 base = resource.substring(0, idx); 142 ext = resource.substring(idx); 143 } else { 144 base = resource; 145 ext = ""; } 147 148 java.net.URL baseurl = (loader != null) ? loader.getResource(resource) : IconManager.class.getClassLoader().getResource(resource); 151 Iterator <String > it = NbBundle.getLocalizingSuffixes(); 152 153 while (it.hasNext()) { 154 String suffix = it.next(); 155 Image i; 156 157 if (suffix.length() == 0) { 158 i = getIcon(resource, loader, false); 159 } else { 160 i = getIcon(base + suffix + ext, loader, true); 161 } 162 163 if (i != null) { 164 localizedCache.put(resource, new ActiveRef<String >(i, localizedCache, resource)); 165 166 return i; 167 } 168 } 169 170 localizedCache.put(resource, NO_ICON); 171 172 return null; 173 } 174 } else { 175 return getIcon(resource, getLoader(), false); 176 } 177 } 178 179 185 private static Image getIcon(String name, ClassLoader loader, boolean localizedQuery) { 186 ActiveRef<String > ref = cache.get(name); 187 Image img = null; 188 189 if (ref == NO_ICON) { 191 return null; 192 } 193 194 if (ref != null) { 195 img = ref.get(); 196 } 197 198 if (img != null) { 200 return img; 201 } 202 203 synchronized (cache) { 204 ref = cache.get(name); 206 207 if (ref == NO_ICON) { 209 return null; 210 } 211 212 if (ref != null) { 213 img = ref.get(); 215 } 216 217 if (img != null) { 218 return img; 220 } 221 222 String n; 224 boolean warn; 225 226 if (name.startsWith("/")) { warn = true; 228 n = name.substring(1); 229 } else { 230 warn = false; 231 n = name; 232 } 233 234 java.net.URL url = (loader != null) ? loader.getResource(n) 236 : IconManager.class.getClassLoader().getResource(n); 237 238 img = (url == null) ? null : Toolkit.getDefaultToolkit().createImage(url); 239 240 if (img != null) { 241 if (warn && extraInitialSlashes.add(name)) { 242 ERR.warning( 243 "Initial slashes in Utilities.loadImage deprecated (cf. #20072): " + 244 name 245 ); } 247 248 Image img2 = toBufferedImage(img); 249 250 name = new String (name).intern(); 253 cache.put(name, new ActiveRef<String >(img2, cache, name)); 254 255 return img2; 256 } else { 258 if (!localizedQuery) { 259 cache.put(name, NO_ICON); 260 } 261 262 return null; 263 } 264 } 265 } 266 267 271 static final Image mergeImages(Image im1, Image im2, int x, int y) { 272 CompositeImageKey k = new CompositeImageKey(im1, im2, x, y); 273 Image cached; 274 275 synchronized (compositeCache) { 276 ActiveRef<CompositeImageKey> r = compositeCache.get(k); 277 278 if (r != null) { 279 cached = r.get(); 280 281 if (cached != null) { 282 return cached; 283 } 284 } 285 286 cached = doMergeImages(im1, im2, x, y); 287 compositeCache.put(k, new ActiveRef<CompositeImageKey>(cached, compositeCache, k)); 288 289 return cached; 290 } 291 } 292 293 296 static final Image toBufferedImage(Image img) { 297 new javax.swing.ImageIcon (img, ""); 299 300 if (img.getHeight(null)*img.getWidth(null) > 24*24) { 301 return img; 302 } 303 java.awt.image.BufferedImage rep = createBufferedImage(img.getWidth(null), img.getHeight(null)); 304 java.awt.Graphics g = rep.createGraphics(); 305 g.drawImage(img, 0, 0, null); 306 g.dispose(); 307 img.flush(); 308 309 return rep; 310 } 311 312 private static void ensureLoaded(Image image) { 313 if ( 314 (Toolkit.getDefaultToolkit().checkImage(image, -1, -1, null) & 315 (ImageObserver.ALLBITS | ImageObserver.FRAMEBITS)) != 0 316 ) { 317 return; 318 } 319 320 synchronized (tracker) { 321 int id = ++mediaTrackerID; 322 323 tracker.addImage(image, id); 324 325 try { 326 tracker.waitForID(id, 0); 327 } catch (InterruptedException e) { 328 System.out.println("INTERRUPTED while loading Image"); 329 } 330 331 assert (tracker.statusID(id, false) == MediaTracker.COMPLETE) : "Image loaded"; 332 tracker.removeImage(image, id); 333 } 334 } 335 336 private static final Image doMergeImages(Image image1, Image image2, int x, int y) { 337 ensureLoaded(image1); 338 ensureLoaded(image2); 339 340 int w = Math.max(image1.getWidth(null), x + image2.getWidth(null)); 341 int h = Math.max(image1.getHeight(null), y + image2.getHeight(null)); 342 boolean bitmask = (image1 instanceof Transparency ) && ((Transparency )image1).getTransparency() != Transparency.TRANSLUCENT 343 && (image2 instanceof Transparency ) && ((Transparency )image2).getTransparency() != Transparency.TRANSLUCENT; 344 345 ColorModel model = colorModel(bitmask? Transparency.BITMASK: Transparency.TRANSLUCENT); 346 java.awt.image.BufferedImage buffImage = new java.awt.image.BufferedImage ( 347 model, model.createCompatibleWritableRaster(w, h), model.isAlphaPremultiplied(), null 348 ); 349 350 java.awt.Graphics g = buffImage.createGraphics(); 351 g.drawImage(image1, 0, 0, null); 352 g.drawImage(image2, x, y, null); 353 g.dispose(); 354 355 return buffImage; 356 } 357 358 359 static final java.awt.image.BufferedImage createBufferedImage(int width, int height) { 360 if (Utilities.isMac()) { 361 return new BufferedImage (width, height, BufferedImage.TYPE_INT_ARGB_PRE); 362 } 363 364 ColorModel model = colorModel(java.awt.Transparency.TRANSLUCENT); 365 java.awt.image.BufferedImage buffImage = new java.awt.image.BufferedImage ( 366 model, model.createCompatibleWritableRaster(width, height), model.isAlphaPremultiplied(), null 367 ); 368 369 return buffImage; 370 } 371 372 static private ColorModel colorModel(int transparency) { 373 ColorModel model; 374 try { 375 model = java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment() 376 .getDefaultScreenDevice().getDefaultConfiguration() 377 .getColorModel(transparency); 378 } 379 catch(HeadlessException he) { 380 model = ColorModel.getRGBdefault(); 381 } 382 383 return model; 384 } 385 386 389 private static class CompositeImageKey { 390 Image baseImage; 391 Image overlayImage; 392 int x; 393 int y; 394 395 CompositeImageKey(Image base, Image overlay, int x, int y) { 396 this.x = x; 397 this.y = y; 398 this.baseImage = base; 399 this.overlayImage = overlay; 400 } 401 402 public boolean equals(Object other) { 403 if (!(other instanceof CompositeImageKey)) { 404 return false; 405 } 406 407 CompositeImageKey k = (CompositeImageKey) other; 408 409 return (x == k.x) && (y == k.y) && (baseImage == k.baseImage) && (overlayImage == k.overlayImage); 410 } 411 412 public int hashCode() { 413 int hash = ((x << 3) ^ y) << 4; 414 hash = hash ^ baseImage.hashCode() ^ overlayImage.hashCode(); 415 416 return hash; 417 } 418 419 public String toString() { 420 return "Composite key for " + baseImage + " + " + overlayImage + " at [" + x + ", " + y + "]"; } 422 } 423 424 425 private static final class ActiveRef<T> extends SoftReference <Image > implements Runnable { 426 private Map <T,ActiveRef<T>> holder; 427 private T key; 428 429 public ActiveRef(Image o, Map <T,ActiveRef<T>> holder, T key) { 430 super(o, Utilities.activeReferenceQueue()); 431 this.holder = holder; 432 this.key = key; 433 } 434 435 public void run() { 436 synchronized (holder) { 437 holder.remove(key); 438 } 439 } 440 } 441 } 443 | Popular Tags |