Source Code Cross Referenced for AbstractPainter.java in  » Swing-Library » swingx » org » jdesktop » swingx » painter » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Swing Library » swingx » org.jdesktop.swingx.painter 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * $Id: AbstractPainter.java,v 1.18 2006/09/18 19:42:07 rbair Exp $
003:         *
004:         * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
005:         * Santa Clara, California 95054, U.S.A. All rights reserved.
006:         *
007:         * This library is free software; you can redistribute it and/or
008:         * modify it under the terms of the GNU Lesser General Public
009:         * License as published by the Free Software Foundation; either
010:         * version 2.1 of the License, or (at your option) any later version.
011:         * 
012:         * This library is distributed in the hope that it will be useful,
013:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
014:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015:         * Lesser General Public License for more details.
016:         * 
017:         * You should have received a copy of the GNU Lesser General Public
018:         * License along with this library; if not, write to the Free Software
019:         * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
020:         */
021:
022:        package org.jdesktop.swingx.painter;
023:
024:        import java.awt.Color;
025:        import java.awt.Composite;
026:        import java.awt.Font;
027:        import java.awt.Graphics2D;
028:        import java.awt.Paint;
029:        import java.awt.RenderingHints;
030:        import java.awt.Shape;
031:        import java.awt.Stroke;
032:        import java.awt.Transparency;
033:        import java.awt.geom.AffineTransform;
034:        import java.awt.geom.RoundRectangle2D;
035:        import java.awt.image.BufferedImage;
036:        import java.awt.image.BufferedImageOp;
037:        import java.lang.ref.SoftReference;
038:        import java.util.HashMap;
039:        import java.util.Map;
040:        import javax.swing.JComponent;
041:        import org.jdesktop.beans.AbstractBean;
042:        import org.jdesktop.swingx.util.PaintUtils;
043:        import org.jdesktop.swingx.util.Resize;
044:
045:        /**
046:         * <p>A convenient base class from which concrete Painter implementations may
047:         * extend. It extends JavaBean and thus provides property change notification
048:         * (which is crucial for the Painter implementations to be available in a
049:         * GUI builder). It also saves off the Graphics2D state in its "saveState" method,
050:         * and restores that state in the "restoreState" method. Sublasses simply need
051:         * to extend AbstractPainter and implement the paintBackground method.
052:         * 
053:         * <p>For example, here is the paintBackground method of BackgroundPainter:
054:         * <pre><code>
055:         *  public void paintBackground(Graphics2D g, JComponent component) {
056:         *      g.setColor(component.getBackground());
057:         *      g.fillRect(0, 0, component.getWidth(), component.getHeight());
058:         *  }
059:         * </code></pre>
060:         * 
061:         * <p>AbstractPainter provides a very useful default implementation of
062:         * the paint method. It:
063:         * <ol>
064:         *  <li>Saves off the old state</li>
065:         *  <li>Sets any specified rendering hints</li>
066:         *  <li>Sets the Clip if there is one</li>
067:         *  <li>Sets the Composite if there is one</li>
068:         *  <li>Delegates to paintBackground</li>
069:         *  <li>Restores the original Graphics2D state</li>
070:         * <ol></p>
071:         *
072:         * <p>Specifying rendering hints can greatly improve the visual impact of your
073:         * applications. For example, by default Swing doesn't do much in the way of
074:         * antialiasing (except for Fonts, but that's another story). Pinstripes don't
075:         * look so good without antialiasing. So if I were going to paint pinstripes, I
076:         * might do it like this:
077:         * <pre><code>
078:         *   PinstripePainter p = new PinstripePainter();
079:         *   p.setAntialiasing(RenderingHints.VALUE_ANTIALIAS_ON);
080:         * </code></pre></p>
081:         *
082:         * <p>You can read more about antialiasing and other rendering hints in the
083:         * java.awt.RenderingHints documentation. <strong>By nature, changing the rendering
084:         * hints may have an impact on performance. Certain hints require more
085:         * computation, others require less</strong></p>
086:         * 
087:         * @author rbair
088:         */
089:        public abstract class AbstractPainter<T extends JComponent> extends
090:                AbstractBean implements  Painter<T> {
091:            //------------------------------------------------- Saved Graphics State
092:            private boolean stateSaved = false;
093:            private Paint oldPaint;
094:            private Font oldFont;
095:            private Stroke oldStroke;
096:            private AffineTransform oldTransform;
097:            private Composite oldComposite;
098:            private Shape oldClip;
099:            private Color oldBackground;
100:            private Color oldColor;
101:            private RenderingHints oldRenderingHints;
102:
103:            //--------------------------------------------------- Instance Variables
104:            /**
105:             * A Shape that is used to clip the graphics area. Anything within this
106:             * clip shape is included in the final output.
107:             */
108:            private Shape clip;
109:            /**
110:             * A Resize value indicating if and how the clip should be resized
111:             * according to the size of the Component
112:             */
113:            private Resize resizeClip = Resize.BOTH;
114:            /**
115:             * The composite to use. By default this is a reasonable AlphaComposite,
116:             * but you may want to specify a different composite
117:             */
118:            private Composite composite;
119:            /**
120:             * RenderingHints to apply when painting
121:             */
122:            private Map<RenderingHints.Key, Object> renderingHints;
123:            /**
124:             * A hint as to whether or not to attempt caching the image
125:             */
126:            private boolean useCache = false;
127:            /**
128:             * The cached image, if useCache is true
129:             */
130:            private SoftReference<BufferedImage> cachedImage;
131:            /**
132:             * The Effects to apply to the results of the paint() operation
133:             */
134:            private Effect[] effects = new Effect[0];
135:
136:            /**
137:             * Creates a new instance of AbstractPainter
138:             */
139:            public AbstractPainter() {
140:                renderingHints = new HashMap<RenderingHints.Key, Object>();
141:            }
142:
143:            /**
144:             * <p>Sets whether to cache the painted image with a SoftReference in a BufferedImage
145:             * between calls. If true, and if the size of the component hasn't changed,
146:             * then the cached image will be used rather than causing a painting operation.</p>
147:             *
148:             * <p>This should be considered a hint, rather than absolute. Several factors may
149:             * force repainting, including low memory, different component sizes, or possibly
150:             * new rendering hint settings, etc.</p>
151:             *
152:             * @param b whether or not to use the cache
153:             */
154:            public void setUseCache(boolean b) {
155:                boolean old = isUseCache();
156:                useCache = b;
157:                firePropertyChange("useCache", old, isUseCache());
158:                //if there was a cached image and I'm no longer using the cache, blow it away
159:                if (cachedImage != null && !isUseCache()) {
160:                    cachedImage = null;
161:                }
162:            }
163:
164:            /**
165:             * @return whether or not the cache should be used
166:             */
167:            public boolean isUseCache() {
168:                return useCache;
169:            }
170:
171:            /**
172:             * <p>Sets the effects to apply to the results of the AbstractPainter's
173:             * painting operation. Some common effects include blurs, shadows, embossing,
174:             * and so forth. If the given effects is a null array, no effects will be used</p>
175:             *
176:             * @param effects the Effects to apply to the results of the AbstractPainter's
177:             *                painting operation
178:             */
179:            public void setEffects(Effect... effects) {
180:                Effect[] old = getEffects();
181:                this .effects = new Effect[effects == null ? 0 : effects.length];
182:                if (effects != null) {
183:                    System.arraycopy(effects, 0, this .effects, 0,
184:                            effects.length);
185:                }
186:                firePropertyChange("effects", old, getEffects());
187:                firePropertyChange("effects", old, getEffects());
188:            }
189:
190:            /**
191:             * <p>A convenience method for specifying the effects to use based on
192:             * BufferedImageOps. These will each be individually wrapped by an ImageEffect
193:             * and then setEffects(Effect... effects) will be called with the resulting
194:             * array</p>
195:             *
196:             * @param filters the BufferedImageOps to wrap as effects
197:             */
198:            public void setEffects(BufferedImageOp... filters) {
199:                Effect[] effects = new Effect[filters == null ? 0
200:                        : filters.length];
201:                if (filters != null) {
202:                    int index = 0;
203:                    for (BufferedImageOp op : filters) {
204:                        effects[index++] = new ImageEffect(op);
205:                    }
206:                }
207:                setEffects(effects);
208:            }
209:
210:            /**
211:             * @return effects a defensive copy of the Effects to apply to the results
212:             *          of the AbstractPainter's painting operation. Will never null
213:             */
214:            public Effect[] getEffects() {
215:                Effect[] results = new Effect[effects.length];
216:                System.arraycopy(effects, 0, results, 0, results.length);
217:                return results;
218:            }
219:
220:            /**
221:             * Specifies the Shape to use for clipping the painting area. This
222:             * may be null
223:             *
224:             * @param clip the Shape to use to clip the area. Whatever is inside this
225:             *        shape will be kept, everything else "clipped". May be null. If
226:             *        null, the clipping is not set on the graphics object
227:             */
228:            public void setClip(Shape clip) {
229:                Shape old = getClip();
230:                this .clip = clip;
231:                firePropertyChange("clip", old, getClip());
232:            }
233:
234:            /**
235:             * @return the clipping shape
236:             */
237:            public Shape getClip() {
238:                return clip;
239:            }
240:
241:            /**
242:             * Specifies the resize behavior of the clip. As with all other properties
243:             * that rely on Resize, the value of the width/height of the shape will
244:             * represent a percentage of the width/height of the component, as a value
245:             * between 0 and 1
246:             *
247:             * @param r value indication whether/how to resize the clip. If null,
248:             *        Resize.NONE will be used
249:             */
250:            public void setResizeClip(Resize r) {
251:                Resize old = getResizeClip();
252:                this .resizeClip = r == null ? Resize.NONE : r;
253:                firePropertyChange("resizeClip", old, getResizeClip());
254:            }
255:
256:            /**
257:             * @return value indication whether/how to resize the clip. Will never be null
258:             */
259:            public Resize getResizeClip() {
260:                return resizeClip;
261:            }
262:
263:            /**
264:             * Sets the Composite to use. For example, you may specify a specific
265:             * AlphaComposite so that when this Painter paints, any content in the
266:             * drawing area is handled properly
267:             *
268:             * @param c The composite to use. If null, then no composite will be
269:             *        specified on the graphics object
270:             */
271:            public void setComposite(Composite c) {
272:                Composite old = getComposite();
273:                this .composite = c;
274:                firePropertyChange("composite", old, getComposite());
275:            }
276:
277:            /**
278:             * @return the composite
279:             */
280:            public Composite getComposite() {
281:                return composite;
282:            }
283:
284:            /**
285:             * @return the technique used for interpolating alpha values. May be one
286:             * of:
287:             * <ul>
288:             *  <li>RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED</li>
289:             *  <li>RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY</li>
290:             *  <li>RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT</li>
291:             * </ul>
292:             */
293:            public Object getAlphaInterpolation() {
294:                return renderingHints
295:                        .get(RenderingHints.KEY_ALPHA_INTERPOLATION);
296:            }
297:
298:            /**
299:             * Sets the technique used for interpolating alpha values.
300:             *
301:             * @param alphaInterpolation
302:             * May be one of:
303:             * <ul>
304:             *  <li>RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED</li>
305:             *  <li>RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY</li>
306:             *  <li>RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT</li>
307:             * </ul>
308:             */
309:            public void setAlphaInterpolation(Object alphaInterpolation) {
310:                if (alphaInterpolation != null
311:                        && !RenderingHints.KEY_ALPHA_INTERPOLATION
312:                                .isCompatibleValue(alphaInterpolation)) {
313:                    throw new IllegalArgumentException(alphaInterpolation
314:                            + " is not an acceptable value");
315:                }
316:                Object old = getAlphaInterpolation();
317:                renderingHints.put(RenderingHints.KEY_ALPHA_INTERPOLATION,
318:                        alphaInterpolation);
319:                firePropertyChange("alphaInterpolation", old,
320:                        getAlphaInterpolation());
321:            }
322:
323:            /**
324:             * @return whether or not to antialias
325:             *          May be one of:
326:             * <ul>
327:             *  <li>RenderingHints.VALUE_ANTIALIAS_DEFAULT</li>
328:             *  <li>RenderingHints.VALUE_ANTIALIAS_OFF</li>
329:             *  <li>RenderingHints.VALUE_ANTIALIAS_ON</li>
330:             * </ul>
331:             */
332:            public Object getAntialiasing() {
333:                return renderingHints.get(RenderingHints.KEY_ANTIALIASING);
334:            }
335:
336:            /**
337:             * Sets whether or not to antialias
338:             * @param antialiasing
339:             *          May be one of:
340:             * <ul>
341:             *  <li>RenderingHints.VALUE_ANTIALIAS_DEFAULT</li>
342:             *  <li>RenderingHints.VALUE_ANTIALIAS_OFF</li>
343:             *  <li>RenderingHints.VALUE_ANTIALIAS_ON</li>
344:             * </ul>
345:             */
346:            public void setAntialiasing(Object antialiasing) {
347:                if (antialiasing != null
348:                        && !RenderingHints.KEY_ANTIALIASING
349:                                .isCompatibleValue(antialiasing)) {
350:                    throw new IllegalArgumentException(antialiasing
351:                            + " is not an acceptable value");
352:                }
353:                Object old = getAntialiasing();
354:                renderingHints.put(RenderingHints.KEY_ANTIALIASING,
355:                        antialiasing);
356:                firePropertyChange("antialiasing", old, getAntialiasing());
357:            }
358:
359:            /**
360:             * @return the technique to use for rendering colors
361:             *          May be one of:
362:             * <ul>
363:             *  <li>RenderingHints.VALUE_COLOR_RENDER_DEFAULT</li>
364:             *  <li>RenderingHints.VALUE_RENDER_QUALITY</li>
365:             *  <li>RenderingHints.VALUE_RENDER_SPEED</li>
366:             * </ul>
367:             */
368:            public Object getColorRendering() {
369:                return renderingHints.get(RenderingHints.KEY_COLOR_RENDERING);
370:            }
371:
372:            /**
373:             * Sets the technique to use for rendering colors
374:             * @param colorRendering
375:             *          May be one of:
376:             * <ul>
377:             *  <li>RenderingHints.VALUE_COLOR_RENDER_DEFAULT</li>
378:             *  <li>RenderingHints.VALUE_RENDER_QUALITY</li>
379:             *  <li>RenderingHints.VALUE_RENDER_SPEED</li>
380:             * </ul>
381:             */
382:            public void setColorRendering(Object colorRendering) {
383:                if (colorRendering != null
384:                        && !RenderingHints.KEY_COLOR_RENDERING
385:                                .isCompatibleValue(colorRendering)) {
386:                    throw new IllegalArgumentException(colorRendering
387:                            + " is not an acceptable value");
388:                }
389:                Object old = getColorRendering();
390:                renderingHints.put(RenderingHints.KEY_COLOR_RENDERING,
391:                        colorRendering);
392:                firePropertyChange("colorRendering", old, getColorRendering());
393:            }
394:
395:            /**
396:             * @return whether or not to dither
397:             *          May be one of:
398:             * <ul>
399:             *  <li>RenderingHints.VALUE_DITHER_DEFAULT</li>
400:             *  <li>RenderingHints.VALUE_DITHER_ENABLE</li>
401:             *  <li>RenderingHints.VALUE_DITHER_DISABLE</li>
402:             * </ul>
403:             */
404:            public Object getDithering() {
405:                return renderingHints.get(RenderingHints.KEY_DITHERING);
406:            }
407:
408:            /**
409:             * Sets whether or not to dither
410:             * @param dithering
411:             *          May be one of:
412:             * <ul>
413:             *  <li>RenderingHints.VALUE_DITHER_DEFAULT</li>
414:             *  <li>RenderingHints.VALUE_DITHER_ENABLE</li>
415:             *  <li>RenderingHints.VALUE_DITHER_DISABLE</li>
416:             * </ul>
417:             */
418:            public void setDithering(Object dithering) {
419:                if (dithering != null
420:                        && !RenderingHints.KEY_DITHERING
421:                                .isCompatibleValue(dithering)) {
422:                    throw new IllegalArgumentException(dithering
423:                            + " is not an acceptable value");
424:                }
425:                Object old = getDithering();
426:                renderingHints.put(RenderingHints.KEY_DITHERING, dithering);
427:                firePropertyChange("dithering", old, getDithering());
428:            }
429:
430:            /**
431:             * @return whether or not to use fractional metrics
432:             *          May be one of:
433:             * <ul>
434:             *  <li>RenderingHints.VALUE_FRACTIONALMETRICS_DEFAULT</li>
435:             *  <li>RenderingHints.VALUE_FRACTIONALMETRICS_OFF</li>
436:             *  <li>RenderingHints.VALUE_FRACTIONALMETRICS_ON</li>
437:             * </ul>
438:             */
439:            public Object getFractionalMetrics() {
440:                return renderingHints.get(RenderingHints.KEY_FRACTIONALMETRICS);
441:            }
442:
443:            /**
444:             * Sets whether or not to use fractional metrics
445:             *
446:             * @param fractionalMetrics
447:             *          May be one of:
448:             * <ul>
449:             *  <li>RenderingHints.VALUE_FRACTIONALMETRICS_DEFAULT</li>
450:             *  <li>RenderingHints.VALUE_FRACTIONALMETRICS_OFF</li>
451:             *  <li>RenderingHints.VALUE_FRACTIONALMETRICS_ON</li>
452:             * </ul>
453:             */
454:            public void setFractionalMetrics(Object fractionalMetrics) {
455:                if (fractionalMetrics != null
456:                        && !RenderingHints.KEY_FRACTIONALMETRICS
457:                                .isCompatibleValue(fractionalMetrics)) {
458:                    throw new IllegalArgumentException(fractionalMetrics
459:                            + " is not an acceptable value");
460:                }
461:                Object old = getFractionalMetrics();
462:                renderingHints.put(RenderingHints.KEY_FRACTIONALMETRICS,
463:                        fractionalMetrics);
464:                firePropertyChange("fractionalMetrics", old,
465:                        getFractionalMetrics());
466:            }
467:
468:            /**
469:             * @return the technique to use for interpolation (used esp. when scaling)
470:             *          May be one of:
471:             * <ul>
472:             *  <li>RenderingHints.VALUE_INTERPOLATION_BICUBIC</li>
473:             *  <li>RenderingHints.VALUE_INTERPOLATION_BILINEAR</li>
474:             *  <li>RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR</li>
475:             * </ul>
476:             */
477:            public Object getInterpolation() {
478:                return renderingHints.get(RenderingHints.KEY_INTERPOLATION);
479:            }
480:
481:            /**
482:             * Sets the technique to use for interpolation (used esp. when scaling)
483:             * @param interpolation
484:             *          May be one of:
485:             * <ul>
486:             *  <li>RenderingHints.VALUE_INTERPOLATION_BICUBIC</li>
487:             *  <li>RenderingHints.VALUE_INTERPOLATION_BILINEAR</li>
488:             *  <li>RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR</li>
489:             * </ul>
490:             */
491:            public void setInterpolation(Object interpolation) {
492:                if (interpolation != null
493:                        && !RenderingHints.KEY_INTERPOLATION
494:                                .isCompatibleValue(interpolation)) {
495:                    throw new IllegalArgumentException(interpolation
496:                            + " is not an acceptable value");
497:                }
498:                Object old = getInterpolation();
499:                renderingHints.put(RenderingHints.KEY_INTERPOLATION,
500:                        interpolation);
501:                firePropertyChange("interpolation", old, getInterpolation());
502:            }
503:
504:            /**
505:             * @return a hint as to techniques to use with regards to rendering quality vs. speed
506:             *          May be one of:
507:             * <ul>
508:             *  <li>RenderingHints.VALUE_RENDER_QUALITY</li>
509:             *  <li>RenderingHints.VALUE_RENDER_SPEED</li>
510:             *  <li>RenderingHints.VALUE_RENDER_DEFAULT</li>
511:             * </ul>
512:             */
513:            public Object getRendering() {
514:                return renderingHints.get(RenderingHints.KEY_RENDERING);
515:            }
516:
517:            /**
518:             * Specifies a hint as to techniques to use with regards to rendering quality vs. speed
519:             *
520:             * @param rendering
521:             *          May be one of:
522:             * <ul>
523:             *  <li>RenderingHints.VALUE_RENDER_QUALITY</li>
524:             *  <li>RenderingHints.VALUE_RENDER_SPEED</li>
525:             *  <li>RenderingHints.VALUE_RENDER_DEFAULT</li>
526:             * </ul>
527:             */
528:            public void setRendering(Object rendering) {
529:                if (rendering != null
530:                        && !RenderingHints.KEY_RENDERING
531:                                .isCompatibleValue(rendering)) {
532:                    throw new IllegalArgumentException(rendering
533:                            + " is not an acceptable value");
534:                }
535:                Object old = getRendering();
536:                renderingHints.put(RenderingHints.KEY_RENDERING, rendering);
537:                firePropertyChange("rendering", old, getRendering());
538:            }
539:
540:            /**
541:             * @return technique for rendering strokes
542:             *          May be one of:
543:             * <ul>
544:             *  <li>RenderingHints.VALUE_STROKE_DEFAULT</li>
545:             *  <li>RenderingHints.VALUE_STROKE_NORMALIZE</li>
546:             *  <li>RenderingHints.VALUE_STROKE_PURE</li>
547:             * </ul>
548:             */
549:            public Object getStrokeControl() {
550:                return renderingHints.get(RenderingHints.KEY_STROKE_CONTROL);
551:            }
552:
553:            /**
554:             * Specifies a technique for rendering strokes
555:             *
556:             * @param strokeControl
557:             *          May be one of:
558:             * <ul>
559:             *  <li>RenderingHints.VALUE_STROKE_DEFAULT</li>
560:             *  <li>RenderingHints.VALUE_STROKE_NORMALIZE</li>
561:             *  <li>RenderingHints.VALUE_STROKE_PURE</li>
562:             * </ul>
563:             */
564:            public void setStrokeControl(Object strokeControl) {
565:                if (strokeControl != null
566:                        && !RenderingHints.KEY_STROKE_CONTROL
567:                                .isCompatibleValue(strokeControl)) {
568:                    throw new IllegalArgumentException(strokeControl
569:                            + " is not an acceptable value");
570:                }
571:                Object old = getStrokeControl();
572:                renderingHints.put(RenderingHints.KEY_STROKE_CONTROL,
573:                        strokeControl);
574:                firePropertyChange("strokeControl", old, getStrokeControl());
575:            }
576:
577:            /**
578:             * @return technique for anti-aliasing text.
579:             *          (TODO this needs to be updated for Mustang. You may use the
580:             *           new Mustang values, and everything will work, but support in
581:             *           the GUI builder and documentation need to be added once we
582:             *           branch for Mustang)<br/>
583:             *          May be one of:
584:             * <ul>
585:             *  <li>RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT</li>
586:             *  <li>RenderingHints.VALUE_TEXT_ANTIALIAS_OFF</li>
587:             *  <li>RenderingHints.VALUE_TEXT_ANTIALIAS_ON</li>
588:             * </ul>
589:             */
590:            public Object getTextAntialiasing() {
591:                return renderingHints.get(RenderingHints.KEY_TEXT_ANTIALIASING);
592:            }
593:
594:            /**
595:             * Sets the technique for anti-aliasing text.
596:             *          (TODO this needs to be updated for Mustang. You may use the
597:             *           new Mustang values, and everything will work, but support in
598:             *           the GUI builder and documentation need to be added once we
599:             *           branch for Mustang)<br/>
600:             *
601:             * @param textAntialiasing
602:             *          May be one of:
603:             * <ul>
604:             *  <li>RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT</li>
605:             *  <li>RenderingHints.VALUE_TEXT_ANTIALIAS_OFF</li>
606:             *  <li>RenderingHints.VALUE_TEXT_ANTIALIAS_ON</li>
607:             * </ul>
608:             */
609:            public void setTextAntialiasing(Object textAntialiasing) {
610:                if (textAntialiasing != null
611:                        && !RenderingHints.KEY_TEXT_ANTIALIASING
612:                                .isCompatibleValue(textAntialiasing)) {
613:                    throw new IllegalArgumentException(textAntialiasing
614:                            + " is not an acceptable value");
615:                }
616:                Object old = getTextAntialiasing();
617:                renderingHints.put(RenderingHints.KEY_TEXT_ANTIALIASING,
618:                        textAntialiasing);
619:                firePropertyChange("textAntialiasing", old,
620:                        getTextAntialiasing());
621:            }
622:
623:            /**
624:             * @return the rendering hint associated with the given key. May return null
625:             */
626:            public Object getRenderingHint(RenderingHints.Key key) {
627:                return renderingHints.get(key);
628:            }
629:
630:            /**
631:             * Set the given hint for the given key. This will end up firing the appropriate
632:             * property change event if the key is recognized. For example, if the key is
633:             * RenderingHints.KEY_ANTIALIASING, then the setAntialiasing method will be
634:             * called firing an "antialiasing" property change event if necessary. If
635:             * the key is not recognized, no event will be fired but the key will be saved.
636:             * The key must not be null
637:             *
638:             * @param key cannot be null
639:             * @param hint must be a hint compatible with the given key
640:             */
641:            public void setRenderingHint(RenderingHints.Key key, Object hint) {
642:                if (key == RenderingHints.KEY_ALPHA_INTERPOLATION) {
643:                    setAlphaInterpolation(hint);
644:                } else if (key == RenderingHints.KEY_ANTIALIASING) {
645:                    setAntialiasing(hint);
646:                } else if (key == RenderingHints.KEY_COLOR_RENDERING) {
647:                    setColorRendering(hint);
648:                } else if (key == RenderingHints.KEY_DITHERING) {
649:                    setDithering(hint);
650:                } else if (key == RenderingHints.KEY_FRACTIONALMETRICS) {
651:                    setFractionalMetrics(hint);
652:                } else if (key == RenderingHints.KEY_INTERPOLATION) {
653:                    setInterpolation(hint);
654:                } else if (key == RenderingHints.KEY_RENDERING) {
655:                    setRendering(hint);
656:                } else if (key == RenderingHints.KEY_STROKE_CONTROL) {
657:                    setStrokeControl(hint);
658:                } else if (key == RenderingHints.KEY_TEXT_ANTIALIASING) {
659:                    setTextAntialiasing(hint);
660:                } else {
661:                    renderingHints.put(key, hint);
662:                }
663:            }
664:
665:            /**
666:             * @return a copy of the map of rendering hints held by this class. This
667:             *         returned value will never be null
668:             */
669:            public Map<RenderingHints.Key, Object> getRenderingHints() {
670:                return new HashMap<RenderingHints.Key, Object>(renderingHints);
671:            }
672:
673:            /**
674:             * Sets the rendering hints to use. This will <strong>replace</strong> the
675:             * rendering hints entirely, clearing any hints that were previously set.
676:             *
677:             * @param renderingHints map of hints. May be null. I null, a new Map of
678:             * rendering hints will be created
679:             */
680:            public void setRenderingHints(
681:                    Map<RenderingHints.Key, Object> renderingHints) {
682:                if (renderingHints != null) {
683:                    this .renderingHints = new HashMap<RenderingHints.Key, Object>(
684:                            renderingHints);
685:                } else {
686:                    this .renderingHints = new HashMap<RenderingHints.Key, Object>();
687:                }
688:                firePropertyChange("renderingHints", null, getRenderingHints());
689:            }
690:
691:            /**
692:             * Saves the state in the given Graphics2D object so that it may be
693:             * restored later.
694:             *
695:             * @param g the Graphics2D object who's state will be saved
696:             */
697:            protected void saveState(Graphics2D g) {
698:                oldPaint = g.getPaint();
699:                oldFont = g.getFont();
700:                oldStroke = g.getStroke();
701:                oldTransform = g.getTransform();
702:                oldComposite = g.getComposite();
703:                oldClip = g.getClip();
704:                oldBackground = g.getBackground();
705:                oldColor = g.getColor();
706:
707:                //save off the old rendering hints
708:                oldRenderingHints = (RenderingHints) g.getRenderingHints()
709:                        .clone();
710:
711:                stateSaved = true;
712:            }
713:
714:            /**
715:             * Restores previously saved state. A call to saveState must have occured
716:             * prior to calling restoreState, or an IllegalStateException will be thrown.
717:             * 
718:             * @param g the Graphics2D object to restore previously saved state to
719:             */
720:            protected void restoreState(Graphics2D g) {
721:                if (!stateSaved) {
722:                    throw new IllegalStateException(
723:                            "A call to saveState must occur "
724:                                    + "prior to calling restoreState");
725:                }
726:
727:                g.setPaint(oldPaint);
728:                g.setFont(oldFont);
729:                g.setTransform(oldTransform);
730:                g.setStroke(oldStroke);
731:                g.setComposite(oldComposite);
732:                g.setClip(oldClip);
733:                g.setBackground(oldBackground);
734:                g.setColor(oldColor);
735:
736:                //restore the rendering hints
737:                g.setRenderingHints(oldRenderingHints);
738:
739:                stateSaved = false;
740:            }
741:
742:            /**
743:             * @inheritDoc
744:             */
745:            public void paint(Graphics2D g, T component) {
746:                saveState(g);
747:
748:                configureGraphics(g, component);
749:
750:                //if I am cacheing, and the cache is not null, and the image has the
751:                //same dimensions as the component, then simply paint the image
752:                BufferedImage image = cachedImage == null ? null : cachedImage
753:                        .get();
754:                if (isUseCache() && image != null
755:                        && image.getWidth() == component.getWidth()
756:                        && image.getHeight() == component.getHeight()) {
757:                    g.drawImage(image, 0, 0, null);
758:                } else {
759:                    Effect[] effects = getEffects();
760:                    if (effects.length > 0 || isUseCache()) {
761:                        image = PaintUtils.createCompatibleImage(component
762:                                .getWidth(), component.getHeight(),
763:                                Transparency.TRANSLUCENT);
764:
765:                        Graphics2D gfx = image.createGraphics();
766:                        configureGraphics(gfx, component);
767:                        paintBackground(gfx, component);
768:                        gfx.dispose();
769:
770:                        for (Effect effect : effects) {
771:                            image = effect.apply(image);
772:                        }
773:
774:                        g.drawImage(image, 0, 0, null);
775:
776:                        if (isUseCache()) {
777:                            cachedImage = new SoftReference<BufferedImage>(
778:                                    image);
779:                        }
780:                    } else {
781:                        paintBackground(g, component);
782:                    }
783:                }
784:
785:                restoreState(g);
786:            }
787:
788:            /**
789:             * Utility method for configuring the given Graphics2D with the rendering hints,
790:             * composite, and clip
791:             */
792:            private void configureGraphics(Graphics2D g, T c) {
793:                Map<RenderingHints.Key, Object> hints = getRenderingHints();
794:                //merge these hints with the existing ones, otherwise I won't inherit
795:                //any of the hints from the Graphics2D
796:                for (Object key : hints.keySet()) {
797:                    Object value = hints.get(key);
798:                    if (value != null) {
799:                        g.setRenderingHint((RenderingHints.Key) key, hints
800:                                .get(key));
801:                    }
802:                }
803:
804:                if (getComposite() != null) {
805:                    g.setComposite(getComposite());
806:                }
807:                Shape clip = getClip();
808:                if (clip != null) {
809:                    //resize the clip if necessary
810:                    double width = 1;
811:                    double height = 1;
812:                    Resize resizeClip = getResizeClip();
813:                    if (resizeClip == Resize.HORIZONTAL
814:                            || resizeClip == Resize.BOTH) {
815:                        width = c.getWidth();
816:                    }
817:                    if (resizeClip == Resize.VERTICAL
818:                            || resizeClip == Resize.BOTH) {
819:                        height = c.getHeight();
820:                    }
821:                    if (clip instanceof  RoundRectangle2D) {
822:                        RoundRectangle2D rect = (RoundRectangle2D) clip;
823:                        clip = new RoundRectangle2D.Double(rect.getX(), rect
824:                                .getY(), width, height, rect.getArcWidth(),
825:                                rect.getArcHeight());
826:                    } else {
827:                        clip = AffineTransform.getScaleInstance(width, height)
828:                                .createTransformedShape(clip);
829:                    }
830:                    g.setClip(clip);
831:                }
832:            }
833:
834:            /**
835:             * Subclasses should implement this method and perform custom painting operations
836:             * here. Common behavior, such as setting the clip and composite, saving and restoring
837:             * state, is performed in the "paint" method automatically, and then delegated here.
838:             *
839:             * @param g The Graphics2D object in which to paint
840:             * @param component The JComponent that the Painter is delegate for.
841:             */
842:            protected abstract void paintBackground(Graphics2D g, T component);
843:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.