001: /*
002: * Copyright (c) 2001-2007 JGoodies Karsten Lentzsch. All Rights Reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * o Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: *
010: * o Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * o Neither the name of JGoodies Karsten Lentzsch nor the names of
015: * its contributors may be used to endorse or promote products derived
016: * from this software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
020: * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
021: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
022: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
025: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
026: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
027: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
028: * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029: */
030:
031: package com.jgoodies.looks.common;
032:
033: import java.awt.Graphics;
034: import java.awt.Graphics2D;
035: import java.awt.GraphicsDevice;
036: import java.awt.PrintGraphics;
037: import java.awt.RenderingHints;
038: import java.awt.Toolkit;
039: import java.awt.print.PrinterGraphics;
040: import java.lang.reflect.InvocationTargetException;
041: import java.lang.reflect.Method;
042: import java.util.HashMap;
043: import java.util.Iterator;
044: import java.util.Map;
045:
046: import javax.swing.JComponent;
047: import javax.swing.plaf.basic.BasicGraphicsUtils;
048:
049: import com.jgoodies.looks.LookUtils;
050:
051: /**
052: * Provides convenience behavior used by the JGoodies Looks.<p>
053: *
054: * <strong>Note:</strong> This class is not part of the public Looks API.
055: * It should be treated as library internal and should not be used by
056: * API users. It may be removed or changed with the Looks version
057: * without further notice.
058: *
059: * @author Karsten Lentzsch
060: * @author Andrej Golovnin
061: * @version $Revision: 1.9 $
062: *
063: * @since 2.0
064: */
065: public final class RenderingUtils {
066:
067: private static final String PROP_DESKTOPHINTS = "awt.font.desktophints";
068:
069: private static final String SWING_UTILITIES2_NAME = LookUtils.IS_JAVA_6_OR_LATER ? "sun.swing.SwingUtilities2"
070: : "com.sun.java.swing.SwingUtilities2";
071:
072: /**
073: * In Java 5 or later, this field holds the public static method
074: * <code>SwingUtilities2#drawStringUnderlinedAt</code> that has been added
075: * for Java 5.
076: */
077: private static Method drawStringUnderlineCharAtMethod = null;
078:
079: static {
080: if (LookUtils.IS_JAVA_5_OR_LATER) {
081: drawStringUnderlineCharAtMethod = getMethodDrawStringUnderlineCharAt();
082: }
083: }
084:
085: private RenderingUtils() {
086: // Overrides default constructor; prevents instantiation.
087: }
088:
089: /**
090: * Draws the string at the specified location underlining the specified
091: * character.
092: *
093: * @param c JComponent that will display the string, may be null
094: * @param g Graphics to draw the text to
095: * @param text String to display
096: * @param underlinedIndex Index of a character in the string to underline
097: * @param x X coordinate to draw the text at
098: * @param y Y coordinate to draw the text at
099: */
100: public static void drawStringUnderlineCharAt(JComponent c,
101: Graphics g, String text, int underlinedIndex, int x, int y) {
102: if (LookUtils.IS_JAVA_5_OR_LATER) {
103: if (drawStringUnderlineCharAtMethod != null) {
104: try {
105: drawStringUnderlineCharAtMethod.invoke(null,
106: new Object[] { c, g, text,
107: new Integer(underlinedIndex),
108: new Integer(x), new Integer(y) });
109: return;
110: } catch (IllegalArgumentException e) {
111: // Use the BasicGraphicsUtils as fallback
112: } catch (IllegalAccessException e) {
113: // Use the BasicGraphicsUtils as fallback
114: } catch (InvocationTargetException e) {
115: // Use the BasicGraphicsUtils as fallback
116: }
117: }
118: Graphics2D g2 = (Graphics2D) g;
119: Map oldRenderingHints = installDesktopHints(g2);
120: BasicGraphicsUtils.drawStringUnderlineCharAt(g, text,
121: underlinedIndex, x, y);
122: if (oldRenderingHints != null) {
123: g2.addRenderingHints(oldRenderingHints);
124: }
125: return;
126: }
127: BasicGraphicsUtils.drawStringUnderlineCharAt(g, text,
128: underlinedIndex, x, y);
129: }
130:
131: // Private Helper Code ****************************************************
132:
133: private static Method getMethodDrawStringUnderlineCharAt() {
134: try {
135: Class clazz = Class.forName(SWING_UTILITIES2_NAME);
136: return clazz.getMethod("drawStringUnderlineCharAt",
137: new Class[] { JComponent.class, Graphics.class,
138: String.class, Integer.TYPE, Integer.TYPE,
139: Integer.TYPE });
140: } catch (ClassNotFoundException e) {
141: // returns null
142: } catch (SecurityException e) {
143: // returns null
144: } catch (NoSuchMethodException e) {
145: // returns null
146: }
147: return null;
148: }
149:
150: private static Map installDesktopHints(Graphics2D g2) {
151: Map oldRenderingHints = null;
152: if (LookUtils.IS_JAVA_6_OR_LATER) {
153: Map desktopHints = desktopHints(g2);
154: if (desktopHints != null && !desktopHints.isEmpty()) {
155: oldRenderingHints = new HashMap(desktopHints.size());
156: RenderingHints.Key key;
157: for (Iterator i = desktopHints.keySet().iterator(); i
158: .hasNext();) {
159: key = (RenderingHints.Key) i.next();
160: oldRenderingHints
161: .put(key, g2.getRenderingHint(key));
162: }
163: g2.addRenderingHints(desktopHints);
164: }
165: }
166: return oldRenderingHints;
167: }
168:
169: private static Map desktopHints(Graphics2D g2) {
170: if (isPrinting(g2)) {
171: return null;
172: }
173: Toolkit toolkit = Toolkit.getDefaultToolkit();
174: GraphicsDevice device = g2.getDeviceConfiguration().getDevice();
175: Map desktopHints = (Map) toolkit
176: .getDesktopProperty(PROP_DESKTOPHINTS + '.'
177: + device.getIDstring());
178: if (desktopHints == null) {
179: desktopHints = (Map) toolkit
180: .getDesktopProperty(PROP_DESKTOPHINTS);
181: }
182: // It is possible to get a non-empty map but with disabled AA.
183: if (desktopHints != null) {
184: Object aaHint = desktopHints
185: .get(RenderingHints.KEY_TEXT_ANTIALIASING);
186: if ((aaHint == RenderingHints.VALUE_TEXT_ANTIALIAS_OFF)
187: || (aaHint == RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT)) {
188: desktopHints = null;
189: }
190: }
191: return desktopHints;
192: }
193:
194: private static boolean isPrinting(Graphics g) {
195: return g instanceof PrintGraphics
196: || g instanceof PrinterGraphics;
197: }
198:
199: }
|