KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > plaf > metal > CachedPainter


1 /*
2  * @(#)CachedPainter.java 1.2 04/02/15
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7 package javax.swing.plaf.metal;
8
9 import java.awt.*;
10 import java.awt.image.*;
11 import javax.swing.Icon JavaDoc;
12 import java.lang.ref.SoftReference JavaDoc;
13 import java.util.*;
14
15 /**
16  * A base class used for icons or images that are expensive to paint.
17  * A subclass will do the following:
18  * <ol>
19  * <li>Invoke <code>paint</code> when you want to paint the image,
20  * if you are implementing <code>Icon</code> you'll invoke this from
21  * <code>paintIcon</code>.
22  * The args argument is useful when additional state is needed.
23  * <li>Override <code>paintToImage</code> to render the image. The code that
24  * lives here is equivalent to what previously would go in
25  * <code>paintIcon</code>, for an <code>Icon</code>.
26  * </ol>
27  *
28  * @version @(#)CachedPainter.java 1.2 04/02/15
29  */

30 abstract class CachedPainter {
31     // CacheMap maps from class to Cache.
32
private static final Map<Object JavaDoc,Cache> cacheMap =
33                    new HashMap<Object JavaDoc,Cache>();
34
35
36     private static Cache getCache(Object JavaDoc key) {
37         synchronized(cacheMap) {
38             Cache cache = cacheMap.get(key);
39             if (cache == null) {
40                 cache = new Cache(1);
41                 cacheMap.put(key, cache);
42             }
43             return cache;
44         }
45     }
46
47     /**
48      * Creates an instance of <code>CachedPainter</code> that will cache up
49      * to <code>cacheCount</code> images of this class.
50      *
51      * @param cacheCount Max number of images to cache
52      */

53     public CachedPainter(int cacheCount) {
54         getCache(getClass()).setMaxCount(cacheCount);
55     }
56
57     /**
58      * Renders the cached image to the the passed in <code>Graphic</code>.
59      * If there is no cached image <code>paintToImage</code> will be invoked.
60      * <code>paintImage</code> is invoked to paint the cached image.
61      */

62     protected void paint(Component c, Graphics g, int x,
63                          int y, int w, int h, Object JavaDoc... args) {
64         if (w <= 0 || h <= 0) {
65             return;
66         }
67         Object JavaDoc key = getClass();
68         GraphicsConfiguration config = c.getGraphicsConfiguration();
69         Cache cache = getCache(key);
70         Image image = cache.getImage(key, config, w, h, args);
71         int attempts = 0;
72         do {
73             boolean draw = false;
74             if (image instanceof VolatileImage) {
75                 // See if we need to recreate the image
76
switch (((VolatileImage)image).validate(config)) {
77                 case VolatileImage.IMAGE_INCOMPATIBLE:
78                     ((VolatileImage)image).flush();
79                     image = null;
80                     break;
81                 case VolatileImage.IMAGE_RESTORED:
82                     draw = true;
83                     break;
84                 }
85             }
86             if (image == null) {
87                 // Recreate the image
88
image = createImage(c, w, h, config);
89                 cache.setImage(key, config, w, h, args, image);
90                 draw = true;
91             }
92             if (draw) {
93                 // Render to the Image
94
Graphics g2 = image.getGraphics();
95                 paintToImage(c, g2, w, h, args);
96                 g2.dispose();
97             }
98
99             // Render to the passed in Graphics
100
paintImage(c, g, x, y, w, h, image, args);
101
102             // If we did this 3 times and the contents are still lost
103
// assume we're painting to a VolatileImage that is bogus and
104
// give up. Presumably we'll be called again to paint.
105
} while ((image instanceof VolatileImage) &&
106                  ((VolatileImage)image).contentsLost() && ++attempts < 3);
107     }
108
109     /**
110      * Paints the representation to cache to the supplied Graphics.
111      *
112      * @param c Component painting to
113      * @param g Graphics to paint to
114      * @param w Width to paint to
115      * @param h Height to paint to
116      * @param args Arguments supplied to <code>paint</code>
117      */

118     protected abstract void paintToImage(Component c, Graphics g,
119                                          int w, int h, Object JavaDoc[] args);
120
121
122     /**
123      * Paints the image to the specified location.
124      *
125      * @param c Component painting to
126      * @param g Graphics to paint to
127      * @param x X coordinate to paint to
128      * @param y Y coordinate to paint to
129      * @param w Width to paint to
130      * @param h Height to paint to
131      * @param image Image to paint
132      * @param args Arguments supplied to <code>paint</code>
133      */

134     protected void paintImage(Component c, Graphics g,
135                               int x, int y, int w, int h, Image image,
136                               Object JavaDoc[] args) {
137         g.drawImage(image, x, y, null);
138     }
139
140     /**
141      * Creates the image to cache. This returns an opaque image, subclasses
142      * that require translucency or transparency will need to override this
143      * method.
144      *
145      * @param c Component painting to
146      * @param w Width of image to create
147      * @param h Height to image to create
148      * @param config GraphicsConfiguration that will be
149      * rendered to, this may be null.
150      */

151     protected Image createImage(Component c, int w, int h,
152                                 GraphicsConfiguration config) {
153         if (config == null) {
154             return new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
155         }
156         return config.createCompatibleVolatileImage(w, h);
157     }
158
159
160     /**
161      * Cache is used to cache an image based on a set of arguments.
162      */

163     private static class Cache {
164         // Maximum number of entries to cache
165
private int maxCount;
166         // The entries.
167
private java.util.List JavaDoc<SoftReference JavaDoc<Entry>> entries;
168
169         Cache(int maxCount) {
170             this.maxCount = maxCount;
171             entries = new ArrayList<SoftReference JavaDoc<Entry>>(maxCount);
172         }
173
174         void setMaxCount(int maxCount) {
175             this.maxCount = maxCount;
176         }
177
178         private Entry getEntry(Object JavaDoc key, GraphicsConfiguration config,
179                                int w, int h, Object JavaDoc[] args) {
180             synchronized(this) {
181                 Entry entry;
182                 for (int counter = entries.size() - 1; counter >= 0;counter--){
183                     entry = entries.get(counter).get();
184                     if (entry == null) {
185                         // SoftReference was invalidated, remove the entry
186
entries.remove(counter);
187                     }
188                     else if (entry.equals(config, w, h, args)) {
189                         // Found the entry, return it.
190
return entry;
191                     }
192                 }
193                 // Entry doesn't exist
194
entry = new Entry(config, w, h, args);
195                 if (entries.size() == maxCount) {
196                     entries.remove(0);
197                 }
198                 entries.add(new SoftReference JavaDoc<Entry>(entry));
199                 return entry;
200             }
201         }
202
203         /**
204          * Returns the cached Image, or null, for the specified arguments.
205          */

206         public Image getImage(Object JavaDoc key, GraphicsConfiguration config,
207                               int w, int h, Object JavaDoc[] args) {
208             Entry entry = getEntry(key, config, w, h, args);
209             return entry.getImage();
210         }
211
212         /**
213          * Sets the cached image for the specified constraints.
214          */

215         public void setImage(Object JavaDoc key, GraphicsConfiguration config,
216                              int w, int h, Object JavaDoc[] args, Image image) {
217             Entry entry = getEntry(key, config, w, h, args);
218             entry.setImage(image);
219         }
220
221
222         /**
223          * Caches set of arguments and Image.
224          */

225         private static class Entry {
226             private GraphicsConfiguration config;
227             private Object JavaDoc[] args;
228             private Image image;
229             private int w;
230             private int h;
231
232             Entry(GraphicsConfiguration config, int w, int h, Object JavaDoc[] args) {
233                 this.config = config;
234                 this.args = args;
235                 this.w = w;
236                 this.h = h;
237             }
238
239             public void setImage(Image image) {
240                 this.image = image;
241             }
242
243             public Image getImage() {
244                 return image;
245             }
246
247             public String JavaDoc toString() {
248                 String JavaDoc value = super.toString() +
249                                "[ graphicsConfig=" + config +
250                                ", image=" + image +
251                                ", w=" + w + ", h=" + h;
252                 if (args != null) {
253                     for (int counter = 0; counter < args.length; counter++) {
254                         value += ", " + args[counter];
255                     }
256                 }
257                 value += "]";
258                 return value;
259             }
260
261             public boolean equals(GraphicsConfiguration config, int w, int h,
262                                   Object JavaDoc[] args){
263                 if (this.w == w && this.h == h &&
264                        ((this.config != null && this.config.equals(config)) ||
265                         (this.config == null && config == null))) {
266                     if (this.args == null && args == null) {
267                         return true;
268                     }
269                     if (this.args != null && args != null &&
270                                 this.args.length == args.length) {
271                         for (int counter = args.length - 1; counter >= 0;
272                              counter--) {
273                             if (!this.args[counter].equals(args[counter])) {
274                                 return false;
275                             }
276                         }
277                         return true;
278                     }
279                 }
280                 return false;
281             }
282         }
283     }
284 }
285
Popular Tags