KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > util > IconManager


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.openide.util;
21
22 import java.awt.Component JavaDoc;
23 import java.awt.HeadlessException JavaDoc;
24 import java.awt.Image JavaDoc;
25 import java.awt.MediaTracker JavaDoc;
26 import java.awt.Toolkit JavaDoc;
27 import java.awt.Transparency JavaDoc;
28 import java.awt.image.BufferedImage JavaDoc;
29 import java.awt.image.ColorModel JavaDoc;
30 import java.awt.image.ImageObserver JavaDoc;
31 import java.lang.ref.SoftReference JavaDoc;
32 import java.util.HashMap JavaDoc;
33 import java.util.HashSet JavaDoc;
34 import java.util.Iterator JavaDoc;
35 import java.util.Map JavaDoc;
36 import java.util.Set JavaDoc;
37 import java.util.logging.Logger JavaDoc;
38
39 /** Registers all loaded images into the AbstractNode, so nothing is loaded twice.
40 *
41 * @author Jaroslav Tulach
42 */

43 final class IconManager extends Object JavaDoc {
44     /** a value that indicates that the icon does not exists */
45     private static final ActiveRef<String JavaDoc> NO_ICON = new ActiveRef<String JavaDoc>(null, null, null);
46
47     private static final Map JavaDoc<String JavaDoc,ActiveRef<String JavaDoc>> cache = new HashMap JavaDoc<String JavaDoc,ActiveRef<String JavaDoc>>(128);
48     private static final Map JavaDoc<String JavaDoc,ActiveRef<String JavaDoc>> localizedCache = new HashMap JavaDoc<String JavaDoc,ActiveRef<String JavaDoc>>(128);
49     private static final Map JavaDoc<CompositeImageKey,ActiveRef<CompositeImageKey>> compositeCache = new HashMap JavaDoc<CompositeImageKey,ActiveRef<CompositeImageKey>>(128);
50
51     /** Resource paths for which we have had to strip initial slash.
52      * @see "#20072"
53      */

54     private static final Set JavaDoc<String JavaDoc> extraInitialSlashes = new HashSet JavaDoc<String JavaDoc>();
55     private static volatile Object JavaDoc currentLoader;
56     private static Lookup.Result<ClassLoader JavaDoc> loaderQuery = null;
57     private static boolean noLoaderWarned = false;
58     private static final Component JavaDoc component = new Component JavaDoc() {
59         };
60
61     private static final MediaTracker JavaDoc tracker = new MediaTracker JavaDoc(component);
62     private static int mediaTrackerID;
63     
64     private static final Logger JavaDoc ERR = Logger.getLogger(IconManager.class.getName());
65
66     /**
67      * Get the class loader from lookup.
68      * Since this is done very frequently, it is wasteful to query lookup each time.
69      * Instead, remember the last result and just listen for changes.
70      */

71     static ClassLoader JavaDoc getLoader() {
72         Object JavaDoc is = currentLoader;
73         if (is instanceof ClassLoader JavaDoc) {
74             return (ClassLoader JavaDoc)is;
75         }
76             
77         currentLoader = Thread.currentThread();
78             
79         if (loaderQuery == null) {
80             loaderQuery = Lookup.getDefault().lookup(new Lookup.Template<ClassLoader JavaDoc>(ClassLoader JavaDoc.class));
81             loaderQuery.addLookupListener(
82                 new LookupListener() {
83                     public void resultChanged(LookupEvent ev) {
84                         ERR.fine("Loader cleared"); // NOI18N
85
currentLoader = null;
86                     }
87                 }
88             );
89         }
90
91         Iterator JavaDoc it = loaderQuery.allInstances().iterator();
92         if (it.hasNext()) {
93             ClassLoader JavaDoc toReturn = (ClassLoader JavaDoc) it.next();
94             if (currentLoader == Thread.currentThread()) {
95                 currentLoader = toReturn;
96             }
97             ERR.fine("Loader computed: " + currentLoader); // NOI18N
98
return toReturn;
99         } else { if (!noLoaderWarned) {
100                 noLoaderWarned = true;
101                 ERR.warning(
102                     "No ClassLoader instance found in " + Lookup.getDefault() // NOI18N
103
);
104             }
105             return null;
106         }
107     }
108
109     static Image JavaDoc getIcon(String JavaDoc resource, boolean localized) {
110         if (localized) {
111             synchronized (localizedCache) {
112                 ActiveRef<String JavaDoc> ref = localizedCache.get(resource);
113                 Image JavaDoc img = null;
114
115                 // no icon for this name (already tested)
116
if (ref == NO_ICON) {
117                     return null;
118                 }
119
120                 if (ref != null) {
121                     // then it is SoftRefrence
122
img = ref.get();
123                 }
124
125                 // icon found
126
if (img != null) {
127                     return img;
128                 }
129
130                 // find localized or base image
131
ClassLoader JavaDoc loader = getLoader();
132
133                 // we'll keep the String probably for long time, optimize it
134
resource = new String JavaDoc(resource).intern(); // NOPMD
135

136                 String JavaDoc base;
137                 String JavaDoc 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 = ""; // NOI18N
146
}
147
148                 // #31008. [PENDING] remove in case package cache is precomputed
149
java.net.URL JavaDoc baseurl = (loader != null) ? loader.getResource(resource) // NOPMD
150
: IconManager.class.getClassLoader().getResource(resource);
151                 Iterator JavaDoc<String JavaDoc> it = NbBundle.getLocalizingSuffixes();
152                 
153                 while (it.hasNext()) {
154                     String JavaDoc suffix = it.next();
155                     Image JavaDoc 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 JavaDoc>(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     /** Finds image for given resource.
180     * @param name name of the resource
181     * @param loader classloader to use for locating it, or null to use classpath
182     * @param localizedQuery whether the name contains some localization suffix
183     * and is not optimized/interned
184     */

185     private static Image JavaDoc getIcon(String JavaDoc name, ClassLoader JavaDoc loader, boolean localizedQuery) {
186         ActiveRef<String JavaDoc> ref = cache.get(name);
187         Image JavaDoc img = null;
188
189         // no icon for this name (already tested)
190
if (ref == NO_ICON) {
191             return null;
192         }
193
194         if (ref != null) {
195             img = ref.get();
196         }
197
198         // icon found
199
if (img != null) {
200             return img;
201         }
202
203         synchronized (cache) {
204             // again under the lock
205
ref = cache.get(name);
206
207             // no icon for this name (already tested)
208
if (ref == NO_ICON) {
209                 return null;
210             }
211
212             if (ref != null) {
213                 // then it is SoftRefrence
214
img = ref.get();
215             }
216
217             if (img != null) {
218                 // cannot be NO_ICON, since it never disappears from the map.
219
return img;
220             }
221
222             // path for bug in classloader
223
String JavaDoc n;
224             boolean warn;
225
226             if (name.startsWith("/")) { // NOI18N
227
warn = true;
228                 n = name.substring(1);
229             } else {
230                 warn = false;
231                 n = name;
232             }
233
234             // we have to load it
235
java.net.URL JavaDoc 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                     ); // NOI18N
246
}
247
248                 Image JavaDoc img2 = toBufferedImage(img);
249
250                 //System.err.println("loading icon " + n + " = " + img2);
251
name = new String JavaDoc(name).intern(); // NOPMD
252

253                 cache.put(name, new ActiveRef<String JavaDoc>(img2, cache, name));
254
255                 return img2;
256             } else { // no icon found
257

258                 if (!localizedQuery) {
259                     cache.put(name, NO_ICON);
260                 }
261
262                 return null;
263             }
264         }
265     }
266
267     /**
268      * Method that attempts to find the merged image in the cache first, then
269      * creates the image if it was not found.
270      */

271     static final Image JavaDoc mergeImages(Image JavaDoc im1, Image JavaDoc im2, int x, int y) {
272         CompositeImageKey k = new CompositeImageKey(im1, im2, x, y);
273         Image JavaDoc 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     /** The method creates a BufferedImage which represents the same Image as the
294      * parameter but consumes less memory.
295      */

296     static final Image JavaDoc toBufferedImage(Image JavaDoc img) {
297         // load the image
298
new javax.swing.ImageIcon JavaDoc(img, "");
299
300         if (img.getHeight(null)*img.getWidth(null) > 24*24) {
301             return img;
302         }
303         java.awt.image.BufferedImage JavaDoc rep = createBufferedImage(img.getWidth(null), img.getHeight(null));
304         java.awt.Graphics JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc doMergeImages(Image JavaDoc image1, Image JavaDoc 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 JavaDoc) && ((Transparency JavaDoc)image1).getTransparency() != Transparency.TRANSLUCENT
343                 && (image2 instanceof Transparency JavaDoc) && ((Transparency JavaDoc)image2).getTransparency() != Transparency.TRANSLUCENT;
344
345         ColorModel JavaDoc model = colorModel(bitmask? Transparency.BITMASK: Transparency.TRANSLUCENT);
346         java.awt.image.BufferedImage JavaDoc buffImage = new java.awt.image.BufferedImage JavaDoc(
347                 model, model.createCompatibleWritableRaster(w, h), model.isAlphaPremultiplied(), null
348             );
349
350         java.awt.Graphics JavaDoc 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     /** Creates BufferedImage with Transparency.TRANSLUCENT */
359     static final java.awt.image.BufferedImage JavaDoc createBufferedImage(int width, int height) {
360         if (Utilities.isMac()) {
361             return new BufferedImage JavaDoc(width, height, BufferedImage.TYPE_INT_ARGB_PRE);
362         }
363
364         ColorModel JavaDoc model = colorModel(java.awt.Transparency.TRANSLUCENT);
365         java.awt.image.BufferedImage JavaDoc buffImage = new java.awt.image.BufferedImage JavaDoc(
366                 model, model.createCompatibleWritableRaster(width, height), model.isAlphaPremultiplied(), null
367             );
368
369         return buffImage;
370     }
371     
372     static private ColorModel JavaDoc colorModel(int transparency) {
373         ColorModel JavaDoc model;
374         try {
375             model = java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment()
376                 .getDefaultScreenDevice().getDefaultConfiguration()
377                 .getColorModel(transparency);
378         }
379         catch(HeadlessException JavaDoc he) {
380             model = ColorModel.getRGBdefault();
381         }
382
383         return model;
384     }
385
386     /**
387      * Key used for composite images -- it holds image identities
388      */

389     private static class CompositeImageKey {
390         Image JavaDoc baseImage;
391         Image JavaDoc overlayImage;
392         int x;
393         int y;
394
395         CompositeImageKey(Image JavaDoc base, Image JavaDoc 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 JavaDoc 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 JavaDoc toString() {
420             return "Composite key for " + baseImage + " + " + overlayImage + " at [" + x + ", " + y + "]"; // NOI18N
421
}
422     }
423
424     /** Cleaning reference. */
425     private static final class ActiveRef<T> extends SoftReference JavaDoc<Image JavaDoc> implements Runnable JavaDoc {
426         private Map JavaDoc<T,ActiveRef<T>> holder;
427         private T key;
428
429         public ActiveRef(Image JavaDoc o, Map JavaDoc<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      // end of ActiveRef
442
}
443
Popular Tags