001: /* ===========================================================
002: * JFreeChart : a free chart library for the Java(tm) platform
003: * ===========================================================
004: *
005: * (C) Copyright 2000-2007, by Object Refinery Limited and Contributors.
006: *
007: * Project Info: http://www.jfree.org/jfreechart/index.html
008: *
009: * This library is free software; you can redistribute it and/or modify it
010: * under the terms of the GNU Lesser General Public License as published by
011: * the Free Software Foundation; either version 2.1 of the License, or
012: * (at your option) any later version.
013: *
014: * This library is distributed in the hope that it will be useful, but
015: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
016: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
017: * License for more details.
018: *
019: * You should have received a copy of the GNU Lesser General Public
020: * License along with this library; if not, write to the Free Software
021: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
022: * USA.
023: *
024: * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
025: * in the United States and other countries.]
026: *
027: * -------------
028: * SWTUtils.java
029: * -------------
030: * (C) Copyright 2006, 2007, by Henry Proudhon and Contributors.
031: *
032: * Original Author: Henry Proudhon (henry.proudhon AT insa-lyon.fr);
033: * Contributor(s): Rainer Blessing;
034: * David Gilbert (david.gilbert@object-refinery.com)
035: *
036: * Changes
037: * -------
038: * 01-Aug-2006 : New class (HP);
039: * 16-Jan-2007 : Use FontData.getHeight() instead of direct field access (RB);
040: * 31-Jan-2007 : moved the dummy JPanel from SWTGraphics2D.java,
041: * added a new convert method for mouse events (HP);
042: */
043:
044: package org.jfree.experimental.swt;
045:
046: import java.awt.event.MouseEvent;
047: import java.awt.geom.Point2D;
048: import java.awt.geom.Rectangle2D;
049:
050: import javax.swing.JPanel;
051:
052: import org.eclipse.swt.SWT;
053: import org.eclipse.swt.graphics.Color;
054: import org.eclipse.swt.graphics.Device;
055: import org.eclipse.swt.graphics.Font;
056: import org.eclipse.swt.graphics.FontData;
057: import org.eclipse.swt.graphics.GC;
058: import org.eclipse.swt.graphics.Point;
059: import org.eclipse.swt.graphics.Rectangle;
060:
061: /**
062: * Utility class gathering some useful and general method.
063: * Mainly convert forth and back graphical stuff between
064: * awt and swt.
065: */
066: public class SWTUtils {
067:
068: private final static String Az = "ABCpqr";
069:
070: /** A dummy JPanel used to provide font metrics. */
071: protected static final JPanel DUMMY_PANEL = new JPanel();
072:
073: /**
074: * Create a <code>FontData</code> object which encapsulate
075: * the essential data to create a swt font. The data is taken
076: * from the provided awt Font.
077: * <p>Generally speaking, given a font size, the returned swt font
078: * will display differently on the screen than the awt one.
079: * Because the SWT toolkit use native graphical ressources whenever
080: * it is possible, this fact is plateform dependent. To address
081: * this issue, it is possible to enforce the method to return
082: * a font with the same size (or at least as close as possible)
083: * as the awt one.
084: * <p>When the object is no more used, the user must explicitely
085: * call the dispose method on the returned font to free the
086: * operating system resources (the garbage collector won't do it).
087: *
088: * @param device The swt device to draw on (display or gc device).
089: * @param font The awt font from which to get the data.
090: * @param ensureSameSize A boolean used to enforce the same size
091: * (in pixels) between the awt font and the newly created swt font.
092: * @return a <code>FontData</code> object.
093: */
094: public static FontData toSwtFontData(Device device,
095: java.awt.Font font, boolean ensureSameSize) {
096: FontData fontData = new FontData();
097: fontData.setName(font.getFamily());
098: int style = SWT.NORMAL;
099: switch (font.getStyle()) {
100: case java.awt.Font.PLAIN:
101: style |= SWT.NORMAL;
102: break;
103: case java.awt.Font.BOLD:
104: style |= SWT.BOLD;
105: break;
106: case java.awt.Font.ITALIC:
107: style |= SWT.ITALIC;
108: break;
109: case (java.awt.Font.ITALIC + java.awt.Font.BOLD):
110: style |= SWT.ITALIC | SWT.BOLD;
111: break;
112: }
113: fontData.setStyle(style);
114: // convert the font size (in pt for awt) to height in pixels for swt
115: int height = (int) Math.round(font.getSize() * 72.0
116: / device.getDPI().y);
117: fontData.setHeight(height);
118: // hack to ensure the newly created swt fonts will be rendered with the
119: // same height as the awt one
120: if (ensureSameSize) {
121: GC tmpGC = new GC(device);
122: Font tmpFont = new Font(device, fontData);
123: tmpGC.setFont(tmpFont);
124: if (tmpGC.textExtent(Az).x > DUMMY_PANEL.getFontMetrics(
125: font).stringWidth(Az)) {
126: while (tmpGC.textExtent(Az).x > DUMMY_PANEL
127: .getFontMetrics(font).stringWidth(Az)) {
128: tmpFont.dispose();
129: height--;
130: fontData.setHeight(height);
131: tmpFont = new Font(device, fontData);
132: tmpGC.setFont(tmpFont);
133: }
134: } else if (tmpGC.textExtent(Az).x < DUMMY_PANEL
135: .getFontMetrics(font).stringWidth(Az)) {
136: while (tmpGC.textExtent(Az).x < DUMMY_PANEL
137: .getFontMetrics(font).stringWidth(Az)) {
138: tmpFont.dispose();
139: height++;
140: fontData.setHeight(height);
141: tmpFont = new Font(device, fontData);
142: tmpGC.setFont(tmpFont);
143: }
144: }
145: tmpFont.dispose();
146: tmpGC.dispose();
147: }
148: return fontData;
149: }
150:
151: /**
152: * Create an awt font by converting as much information
153: * as possible from the provided swt <code>FontData</code>.
154: * <p>Generally speaking, given a font size, an swt font will
155: * display differently on the screen than the corresponding awt
156: * one. Because the SWT toolkit use native graphical ressources whenever
157: * it is possible, this fact is plateform dependent. To address
158: * this issue, it is possible to enforce the method to return
159: * an awt font with the same height as the swt one.
160: *
161: * @param device The swt device being drawn on (display or gc device).
162: * @param fontData The swt font to convert.
163: * @param ensureSameSize A boolean used to enforce the same size
164: * (in pixels) between the swt font and the newly created awt font.
165: * @return An awt font converted from the provided swt font.
166: */
167: public static java.awt.Font toAwtFont(Device device,
168: FontData fontData, boolean ensureSameSize) {
169: int style;
170: switch (fontData.getStyle()) {
171: case SWT.NORMAL:
172: style = java.awt.Font.PLAIN;
173: break;
174: case SWT.ITALIC:
175: style = java.awt.Font.ITALIC;
176: break;
177: case SWT.BOLD:
178: style = java.awt.Font.BOLD;
179: break;
180: default:
181: style = java.awt.Font.PLAIN;
182: break;
183: }
184: int height = (int) Math.round(fontData.getHeight()
185: * device.getDPI().y / 72.0);
186: // hack to ensure the newly created awt fonts will be rendered with the
187: // same height as the swt one
188: if (ensureSameSize) {
189: GC tmpGC = new GC(device);
190: Font tmpFont = new Font(device, fontData);
191: tmpGC.setFont(tmpFont);
192: JPanel DUMMY_PANEL = new JPanel();
193: java.awt.Font tmpAwtFont = new java.awt.Font(fontData
194: .getName(), style, height);
195: if (DUMMY_PANEL.getFontMetrics(tmpAwtFont).stringWidth(Az) > tmpGC
196: .textExtent(Az).x) {
197: while (DUMMY_PANEL.getFontMetrics(tmpAwtFont)
198: .stringWidth(Az) > tmpGC.textExtent(Az).x) {
199: height--;
200: tmpAwtFont = new java.awt.Font(fontData.getName(),
201: style, height);
202: }
203: } else if (DUMMY_PANEL.getFontMetrics(tmpAwtFont)
204: .stringWidth(Az) < tmpGC.textExtent(Az).x) {
205: while (DUMMY_PANEL.getFontMetrics(tmpAwtFont)
206: .stringWidth(Az) < tmpGC.textExtent(Az).x) {
207: height++;
208: tmpAwtFont = new java.awt.Font(fontData.getName(),
209: style, height);
210: }
211: }
212: tmpFont.dispose();
213: tmpGC.dispose();
214: }
215: return new java.awt.Font(fontData.getName(), style, height);
216: }
217:
218: /**
219: * Create an awt font by converting as much information
220: * as possible from the provided swt <code>Font</code>.
221: *
222: * @param device The swt device to draw on (display or gc device).
223: * @param font The swt font to convert.
224: * @return An awt font converted from the provided swt font.
225: */
226: public static java.awt.Font toAwtFont(Device device, Font font) {
227: FontData fontData = font.getFontData()[0];
228: return toAwtFont(device, fontData, true);
229: }
230:
231: /**
232: * Creates an awt color instance to match the rgb values
233: * of the specified swt color.
234: *
235: * @param color The swt color to match.
236: * @return an awt color abject.
237: */
238: public static java.awt.Color toAwtColor(Color color) {
239: return new java.awt.Color(color.getRed(), color.getGreen(),
240: color.getBlue());
241: }
242:
243: /**
244: * Creates a swt color instance to match the rgb values
245: * of the specified awt paint. For now, this method test
246: * if the paint is a color and then return the adequate
247: * swt color. Otherwise plain black is assumed.
248: *
249: * @param device The swt device to draw on (display or gc device).
250: * @param paint The awt color to match.
251: * @return a swt color object.
252: */
253: public static Color toSwtColor(Device device, java.awt.Paint paint) {
254: java.awt.Color color;
255: if (paint instanceof java.awt.Color) {
256: color = (java.awt.Color) paint;
257: } else {
258: try {
259: throw new Exception(
260: "only color is supported at present... "
261: + "setting paint to uniform black color");
262: } catch (Exception e) {
263: e.printStackTrace();
264: color = new java.awt.Color(0, 0, 0);
265: }
266: }
267: return new org.eclipse.swt.graphics.Color(device, color
268: .getRed(), color.getGreen(), color.getBlue());
269: }
270:
271: /**
272: * Creates a swt color instance to match the rgb values
273: * of the specified awt color. alpha channel is not supported.
274: * Note that the dispose method will need to be called on the
275: * returned object.
276: *
277: * @param device The swt device to draw on (display or gc device).
278: * @param color The awt color to match.
279: * @return a swt color object.
280: */
281: public static Color toSwtColor(Device device, java.awt.Color color) {
282: return new org.eclipse.swt.graphics.Color(device, color
283: .getRed(), color.getGreen(), color.getBlue());
284: }
285:
286: /**
287: * Transform an awt Rectangle2d instance into a swt one.
288: * The coordinates are rounded to integer for the swt object.
289: * @param rect2d The awt rectangle to map.
290: * @return an swt <code>Rectangle</code> object.
291: */
292: public static Rectangle toSwtRectangle(Rectangle2D rect2d) {
293: return new Rectangle((int) Math.round(rect2d.getMinX()),
294: (int) Math.round(rect2d.getMinY()), (int) Math
295: .round(rect2d.getWidth()), (int) Math
296: .round(rect2d.getHeight()));
297: }
298:
299: /**
300: * Transform a swt Rectangle instance into an awt one.
301: * @param rect the swt <code>Rectangle</code>
302: * @return a Rectangle2D.Double instance with
303: * the eappropriate location and size.
304: */
305: public static Rectangle2D toAwtRectangle(Rectangle rect) {
306: Rectangle2D rect2d = new Rectangle2D.Double();
307: rect2d.setRect(rect.x, rect.y, rect.width, rect.height);
308: return rect2d;
309: }
310:
311: /**
312: * Returns an AWT point with the same coordinates as the specified
313: * SWT point.
314: *
315: * @param p the SWT point (<code>null</code> not permitted).
316: *
317: * @return An AWT point with the same coordinates as <code>p</code>.
318: *
319: * @see #toSwtPoint(java.awt.Point)
320: */
321: public static Point2D toAwtPoint(Point p) {
322: return new java.awt.Point(p.x, p.y);
323: }
324:
325: /**
326: * Returns an SWT point with the same coordinates as the specified
327: * AWT point.
328: *
329: * @param p the AWT point (<code>null</code> not permitted).
330: *
331: * @return An SWT point with the same coordinates as <code>p</code>.
332: *
333: * @see #toAwtPoint(Point)
334: */
335: public static Point toSwtPoint(java.awt.Point p) {
336: return new Point(p.x, p.y);
337: }
338:
339: /**
340: * Returns an SWT point with the same coordinates as the specified AWT
341: * point (rounded to integer values).
342: *
343: * @param p the AWT point (<code>null</code> not permitted).
344: *
345: * @return An SWT point with the same coordinates as <code>p</code>.
346: *
347: * @see #toAwtPoint(Point)
348: */
349: public static Point toSwtPoint(java.awt.geom.Point2D p) {
350: return new Point((int) Math.round(p.getX()), (int) Math.round(p
351: .getY()));
352: }
353:
354: /**
355: * Creates an AWT <code>MouseEvent</code> from a swt event.
356: * This method helps passing SWT mouse event to awt components.
357: * @param event The swt event.
358: * @return A AWT mouse event based on the given SWT event.
359: */
360: public static MouseEvent toAwtMouseEvent(
361: org.eclipse.swt.widgets.Event event) {
362: MouseEvent awtMouseEvent = new MouseEvent(DUMMY_PANEL, event
363: .hashCode(), (long) event.time, SWT.NONE, event.x,
364: event.y, 1, false);
365: return awtMouseEvent;
366: }
367: }
|