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 ensmp.fr);
033 * Contributor(s): Rainer Blessing;
034 * David Gilbert (david.gilbert@object-refinery.com);
035 * Christoph Beck.
036 *
037 * Changes
038 * -------
039 * 01-Aug-2006 : New class (HP);
040 * 16-Jan-2007 : Use FontData.getHeight() instead of direct field access (RB);
041 * 31-Jan-2007 : Moved the dummy JPanel from SWTGraphics2D.java,
042 * added a new convert method for mouse events (HP);
043 * 12-Jul-2007 : Improved the mouse event conversion with buttons
044 * and modifiers handling, patch sent by Christoph Beck (HP);
045 * 27-Aug-2007 : Modified toAwtMouseEvent signature (HP).
046 *
047 */
048
049 package org.jfree.experimental.swt;
050
051 import java.awt.event.InputEvent;
052 import java.awt.event.MouseEvent;
053 import java.awt.geom.Point2D;
054 import java.awt.geom.Rectangle2D;
055
056 import javax.swing.JPanel;
057
058 import org.eclipse.swt.SWT;
059 import org.eclipse.swt.graphics.Color;
060 import org.eclipse.swt.graphics.Device;
061 import org.eclipse.swt.graphics.Font;
062 import org.eclipse.swt.graphics.FontData;
063 import org.eclipse.swt.graphics.GC;
064 import org.eclipse.swt.graphics.Point;
065 import org.eclipse.swt.graphics.Rectangle;
066
067 /**
068 * Utility class gathering some useful and general method.
069 * Mainly convert forth and back graphical stuff between
070 * awt and swt.
071 */
072 public class SWTUtils {
073
074 private final static String Az = "ABCpqr";
075
076 /** A dummy JPanel used to provide font metrics. */
077 protected static final JPanel DUMMY_PANEL = new JPanel();
078
079 /**
080 * Create a <code>FontData</code> object which encapsulate
081 * the essential data to create a swt font. The data is taken
082 * from the provided awt Font.
083 * <p>Generally speaking, given a font size, the returned swt font
084 * will display differently on the screen than the awt one.
085 * Because the SWT toolkit use native graphical resources whenever
086 * it is possible, this fact is platform dependent. To address
087 * this issue, it is possible to enforce the method to return
088 * a font with the same size (or at least as close as possible)
089 * as the awt one.
090 * <p>When the object is no more used, the user must explicitly
091 * call the dispose method on the returned font to free the
092 * operating system resources (the garbage collector won't do it).
093 *
094 * @param device The swt device to draw on (display or gc device).
095 * @param font The awt font from which to get the data.
096 * @param ensureSameSize A boolean used to enforce the same size
097 * (in pixels) between the awt font and the newly created swt font.
098 * @return a <code>FontData</code> object.
099 */
100 public static FontData toSwtFontData(Device device, java.awt.Font font,
101 boolean ensureSameSize) {
102 FontData fontData = new FontData();
103 fontData.setName(font.getFamily());
104 int style = SWT.NORMAL;
105 switch (font.getStyle()) {
106 case java.awt.Font.PLAIN:
107 style |= SWT.NORMAL;
108 break;
109 case java.awt.Font.BOLD:
110 style |= SWT.BOLD;
111 break;
112 case java.awt.Font.ITALIC:
113 style |= SWT.ITALIC;
114 break;
115 case (java.awt.Font.ITALIC + java.awt.Font.BOLD):
116 style |= SWT.ITALIC | SWT.BOLD;
117 break;
118 }
119 fontData.setStyle(style);
120 // convert the font size (in pt for awt) to height in pixels for swt
121 int height = (int) Math.round(font.getSize() * 72.0
122 / device.getDPI().y);
123 fontData.setHeight(height);
124 // hack to ensure the newly created swt fonts will be rendered with the
125 // same height as the awt one
126 if (ensureSameSize) {
127 GC tmpGC = new GC(device);
128 Font tmpFont = new Font(device, fontData);
129 tmpGC.setFont(tmpFont);
130 if (tmpGC.textExtent(Az).x
131 > DUMMY_PANEL.getFontMetrics(font).stringWidth(Az)) {
132 while (tmpGC.textExtent(Az).x
133 > DUMMY_PANEL.getFontMetrics(font).stringWidth(Az)) {
134 tmpFont.dispose();
135 height--;
136 fontData.setHeight(height);
137 tmpFont = new Font(device, fontData);
138 tmpGC.setFont(tmpFont);
139 }
140 }
141 else if (tmpGC.textExtent(Az).x
142 < DUMMY_PANEL.getFontMetrics(font).stringWidth(Az)) {
143 while (tmpGC.textExtent(Az).x
144 < DUMMY_PANEL.getFontMetrics(font).stringWidth(Az)) {
145 tmpFont.dispose();
146 height++;
147 fontData.setHeight(height);
148 tmpFont = new Font(device, fontData);
149 tmpGC.setFont(tmpFont);
150 }
151 }
152 tmpFont.dispose();
153 tmpGC.dispose();
154 }
155 return fontData;
156 }
157
158 /**
159 * Create an awt font by converting as much information
160 * as possible from the provided swt <code>FontData</code>.
161 * <p>Generally speaking, given a font size, an swt font will
162 * display differently on the screen than the corresponding awt
163 * one. Because the SWT toolkit use native graphical ressources whenever
164 * it is possible, this fact is platform dependent. To address
165 * this issue, it is possible to enforce the method to return
166 * an awt font with the same height as the swt one.
167 *
168 * @param device The swt device being drawn on (display or gc device).
169 * @param fontData The swt font to convert.
170 * @param ensureSameSize A boolean used to enforce the same size
171 * (in pixels) between the swt font and the newly created awt font.
172 * @return An awt font converted from the provided swt font.
173 */
174 public static java.awt.Font toAwtFont(Device device, FontData fontData,
175 boolean ensureSameSize) {
176 int style;
177 switch (fontData.getStyle()) {
178 case SWT.NORMAL:
179 style = java.awt.Font.PLAIN;
180 break;
181 case SWT.ITALIC:
182 style = java.awt.Font.ITALIC;
183 break;
184 case SWT.BOLD:
185 style = java.awt.Font.BOLD;
186 break;
187 default:
188 style = java.awt.Font.PLAIN;
189 break;
190 }
191 int height = (int) Math.round(fontData.getHeight() * device.getDPI().y
192 / 72.0);
193 // hack to ensure the newly created awt fonts will be rendered with the
194 // same height as the swt one
195 if (ensureSameSize) {
196 GC tmpGC = new GC(device);
197 Font tmpFont = new Font(device, fontData);
198 tmpGC.setFont(tmpFont);
199 JPanel DUMMY_PANEL = new JPanel();
200 java.awt.Font tmpAwtFont = new java.awt.Font(fontData.getName(),
201 style, height);
202 if (DUMMY_PANEL.getFontMetrics(tmpAwtFont).stringWidth(Az)
203 > tmpGC.textExtent(Az).x) {
204 while (DUMMY_PANEL.getFontMetrics(tmpAwtFont).stringWidth(Az)
205 > tmpGC.textExtent(Az).x) {
206 height--;
207 tmpAwtFont = new java.awt.Font(fontData.getName(), style,
208 height);
209 }
210 }
211 else if (DUMMY_PANEL.getFontMetrics(tmpAwtFont).stringWidth(Az)
212 < tmpGC.textExtent(Az).x) {
213 while (DUMMY_PANEL.getFontMetrics(tmpAwtFont).stringWidth(Az)
214 < tmpGC.textExtent(Az).x) {
215 height++;
216 tmpAwtFont = new java.awt.Font(fontData.getName(), style,
217 height);
218 }
219 }
220 tmpFont.dispose();
221 tmpGC.dispose();
222 }
223 return new java.awt.Font(fontData.getName(), style, height);
224 }
225
226 /**
227 * Create an awt font by converting as much information
228 * as possible from the provided swt <code>Font</code>.
229 *
230 * @param device The swt device to draw on (display or gc device).
231 * @param font The swt font to convert.
232 * @return An awt font converted from the provided swt font.
233 */
234 public static java.awt.Font toAwtFont(Device device, Font font) {
235 FontData fontData = font.getFontData()[0];
236 return toAwtFont(device, fontData, true);
237 }
238
239 /**
240 * Creates an awt color instance to match the rgb values
241 * of the specified swt color.
242 *
243 * @param color The swt color to match.
244 * @return an awt color abject.
245 */
246 public static java.awt.Color toAwtColor(Color color) {
247 return new java.awt.Color(color.getRed(), color.getGreen(),
248 color.getBlue());
249 }
250
251 /**
252 * Creates a swt color instance to match the rgb values
253 * of the specified awt paint. For now, this method test
254 * if the paint is a color and then return the adequate
255 * swt color. Otherwise plain black is assumed.
256 *
257 * @param device The swt device to draw on (display or gc device).
258 * @param paint The awt color to match.
259 * @return a swt color object.
260 */
261 public static Color toSwtColor(Device device, java.awt.Paint paint) {
262 java.awt.Color color;
263 if (paint instanceof java.awt.Color) {
264 color = (java.awt.Color) paint;
265 }
266 else {
267 try {
268 throw new Exception("only color is supported at present... "
269 + "setting paint to uniform black color" );
270 }
271 catch (Exception e) {
272 e.printStackTrace();
273 color = new java.awt.Color(0, 0, 0);
274 }
275 }
276 return new org.eclipse.swt.graphics.Color(device,
277 color.getRed(), color.getGreen(), color.getBlue());
278 }
279
280 /**
281 * Creates a swt color instance to match the rgb values
282 * of the specified awt color. alpha channel is not supported.
283 * Note that the dispose method will need to be called on the
284 * returned object.
285 *
286 * @param device The swt device to draw on (display or gc device).
287 * @param color The awt color to match.
288 * @return a swt color object.
289 */
290 public static Color toSwtColor(Device device, java.awt.Color color) {
291 return new org.eclipse.swt.graphics.Color(device,
292 color.getRed(), color.getGreen(), color.getBlue());
293 }
294
295 /**
296 * Transform an awt Rectangle2d instance into a swt one.
297 * The coordinates are rounded to integer for the swt object.
298 * @param rect2d The awt rectangle to map.
299 * @return an swt <code>Rectangle</code> object.
300 */
301 public static Rectangle toSwtRectangle(Rectangle2D rect2d) {
302 return new Rectangle(
303 (int) Math.round(rect2d.getMinX()),
304 (int) Math.round(rect2d.getMinY()),
305 (int) Math.round(rect2d.getWidth()),
306 (int) Math.round(rect2d.getHeight())
307 );
308 }
309
310 /**
311 * Transform a swt Rectangle instance into an awt one.
312 * @param rect the swt <code>Rectangle</code>
313 * @return a Rectangle2D.Double instance with
314 * the eappropriate location and size.
315 */
316 public static Rectangle2D toAwtRectangle(Rectangle rect) {
317 Rectangle2D rect2d = new Rectangle2D.Double();
318 rect2d.setRect(rect.x, rect.y, rect.width, rect.height);
319 return rect2d;
320 }
321
322 /**
323 * Returns an AWT point with the same coordinates as the specified
324 * SWT point.
325 *
326 * @param p the SWT point (<code>null</code> not permitted).
327 *
328 * @return An AWT point with the same coordinates as <code>p</code>.
329 *
330 * @see #toSwtPoint(java.awt.Point)
331 */
332 public static Point2D toAwtPoint(Point p) {
333 return new java.awt.Point(p.x, p.y);
334 }
335
336 /**
337 * Returns an SWT point with the same coordinates as the specified
338 * AWT point.
339 *
340 * @param p the AWT point (<code>null</code> not permitted).
341 *
342 * @return An SWT point with the same coordinates as <code>p</code>.
343 *
344 * @see #toAwtPoint(Point)
345 */
346 public static Point toSwtPoint(java.awt.Point p) {
347 return new Point(p.x, p.y);
348 }
349
350 /**
351 * Returns an SWT point with the same coordinates as the specified AWT
352 * point (rounded to integer values).
353 *
354 * @param p the AWT point (<code>null</code> not permitted).
355 *
356 * @return An SWT point with the same coordinates as <code>p</code>.
357 *
358 * @see #toAwtPoint(Point)
359 */
360 public static Point toSwtPoint(java.awt.geom.Point2D p) {
361 return new Point((int) Math.round(p.getX()),
362 (int) Math.round(p.getY()));
363 }
364
365 /**
366 * Creates an AWT <code>MouseEvent</code> from a swt event.
367 * This method helps passing SWT mouse event to awt components.
368 * @param event The swt event.
369 * @return A AWT mouse event based on the given SWT event.
370 */
371 public static MouseEvent toAwtMouseEvent(org.eclipse.swt.events.MouseEvent event) {
372 int button = MouseEvent.NOBUTTON;
373 switch (event.button) {
374 case 1: button = MouseEvent.BUTTON1; break;
375 case 2: button = MouseEvent.BUTTON2; break;
376 case 3: button = MouseEvent.BUTTON3; break;
377 }
378 int modifiers = 0;
379 if ((event.stateMask & SWT.CTRL) != 0) {
380 modifiers |= InputEvent.CTRL_DOWN_MASK;
381 }
382 if ((event.stateMask & SWT.SHIFT) != 0) {
383 modifiers |= InputEvent.SHIFT_DOWN_MASK;
384 }
385 if ((event.stateMask & SWT.ALT) != 0) {
386 modifiers |= InputEvent.ALT_DOWN_MASK;
387 }
388 MouseEvent awtMouseEvent = new MouseEvent(DUMMY_PANEL, event.hashCode(),
389 event.time, modifiers, event.x, event.y, 1, false, button);
390 return awtMouseEvent;
391 }
392
393 }