Draw Graphics2D stuff on a swt composite : SWT AWT Swing « SWT « Java Tutorial






/* 
 * JFreeChart : a free chart library for the Java(tm) platform
 * 
 *
 * (C) Copyright 2000-2009, by Object Refinery Limited and Contributors.
 *
 * Project Info:  http://www.jfree.org/jfreechart/index.html
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
 * USA.
 *
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
 * in the United States and other countries.]
 *
 * ------------------
 * SWTGraphics2D.java
 * ------------------
 * (C) Copyright 2006-2008, by Henry Proudhon and Contributors.
 *
 * Original Author:  Henry Proudhon (henry.proudhon AT ensmp.fr);
 * Contributor(s):   Cedric Chabanois (cchabanois AT no-log.org);
 *                   David Gilbert (for Object Refinery Limited);
 *                   Ronnie Duan (see bug report 2583891);
 *
 * Changes
 * -------
 * 14-Jun-2006 : New class (HP);
 * 29-Jan-2007 : Fixed the fillRect method (HP);
 * 31-Jan-2007 : Moved the dummy JPanel to SWTUtils.java,
 *               implemented the drawLine method (HP);
 * 07-Apr-2007 : Dispose some of the swt ressources,
 *               thanks to silent for pointing this out (HP);
 * 23-May-2007 : Removed resource leaks by adding a resource pool (CC);
 * 15-Jun-2007 : Fixed compile error for JDK 1.4 (DG);
 * 22-Oct-2007 : Implemented clipping (HP);
 * 22-Oct-2007 : Implemented some AlphaComposite support (HP);
 * 23-Oct-2007 : Added mechanism for storing RenderingHints (which are
 *               still ignored at this point) (DG);
 * 23-Oct-2007 : Implemented drawPolygon(), drawPolyline(), drawOval(),
 *               fillOval(), drawArc() and fillArc() (DG);
 * 27-Nov-2007 : Implemented a couple of drawImage() methods (DG);
 * 18-Nov-2008 : Check for GradientPaint in setPaint() method (DG);
 * 27-Feb-2009 : Implemented fillPolygon() - see bug 2583891 (DG);
 *
 */

import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.Image;
import java.awt.Paint;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.RenderingHints.Key;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
import java.awt.geom.PathIterator;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ImageObserver;
import java.awt.image.RenderedImage;
import java.awt.image.renderable.RenderableImage;
import java.text.AttributedCharacterIterator;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.Path;
import org.eclipse.swt.graphics.Resource;
import org.eclipse.swt.graphics.Transform;

/**
 * This is a class utility to draw Graphics2D stuff on a swt composite.
 * It is presently developed to use JFreeChart with the Standard
 * Widget Toolkit but may be of a wider use later.
 */
public class SWTGraphics2D extends Graphics2D {

    /** The swt graphic composite */
    private GC gc;

    /**
     * The rendering hints.  For now, these are not used, but at least the
     * basic mechanism is present.
     */
    private RenderingHints hints;

    /** A reference to the compositing rule to apply. This is necessary
     * due to the poor compositing interface of the SWT toolkit. */
    private java.awt.Composite composite;

    /** A HashMap to store the Swt color resources. */
    private Map colorsPool = new HashMap();

    /** A HashMap to store the Swt font resources. */
    private Map fontsPool = new HashMap();

    /** A HashMap to store the Swt transform resources. */
    private Map transformsPool = new HashMap();

    /** A List to store the Swt resources. */
    private List resourcePool = new ArrayList();

    /**
     * Creates a new instance.
     *
     * @param gc  the graphics context.
     */
    public SWTGraphics2D(GC gc) {
        super();
        this.gc = gc;
        this.hints = new RenderingHints(null);
        this.composite = AlphaComposite.getInstance(AlphaComposite.SRC, 1.0f);
    }

    /**
     * Not implemented yet - see {@link Graphics#create()}.
     *
     * @return <code>null</code>.
     */
    public Graphics create() {
        // TODO Auto-generated method stub
        return null;
    }

    /**
     * Not implemented yet - see {@link Graphics2D#getDeviceConfiguration()}.
     *
     * @return <code>null</code>.
     */
    public GraphicsConfiguration getDeviceConfiguration() {
        // TODO Auto-generated method stub
        return null;
    }

    /**
     * Returns the current value for the specified hint key, or
     * <code>null</code> if no value is set.
     *
     * @param hintKey  the hint key (<code>null</code> permitted).
     *
     * @return The hint value, or <code>null</code>.
     *
     * @see #setRenderingHint(RenderingHints.Key, Object)
     */
    public Object getRenderingHint(Key hintKey) {
        return this.hints.get(hintKey);
    }

    /**
     * Sets the value for a rendering hint.  For now, this graphics context
     * ignores all hints.
     *
     * @param hintKey  the key (<code>null</code> not permitted).
     * @param hintValue  the value (must be compatible with the specified key).
     *
     * @throws IllegalArgumentException if <code>hintValue</code> is not
     *         compatible with the <code>hintKey</code>.
     *
     * @see #getRenderingHint(RenderingHints.Key)
     */
    public void setRenderingHint(Key hintKey, Object hintValue) {
        this.hints.put(hintKey, hintValue);
    }

    /**
     * Returns a copy of the hints collection for this graphics context.
     *
     * @return A copy of the hints collection.
     */
    public RenderingHints getRenderingHints() {
        return (RenderingHints) this.hints.clone();
    }

    /**
     * Adds the hints in the specified map to the graphics context, replacing
     * any existing hints.  For now, this graphics context ignores all hints.
     *
     * @param hints  the hints (<code>null</code> not permitted).
     *
     * @see #setRenderingHints(Map)
     */
    public void addRenderingHints(Map hints) {
        this.hints.putAll(hints);
    }

    /**
     * Replaces the existing hints with those contained in the specified
     * map.  Note that, for now, this graphics context ignores all hints.
     *
     * @param hints  the hints (<code>null</code> not permitted).
     *
     * @see #addRenderingHints(Map)
     */
    public void setRenderingHints(Map hints) {
        if (hints == null) {
            throw new NullPointerException("Null 'hints' argument.");
        }
        this.hints = new RenderingHints(hints);
    }

    /**
     * Returns the current paint for this graphics context.
     *
     * @return The current paint.
     *
     * @see #setPaint(Paint)
     */
    public Paint getPaint() {
        // TODO: it might be a good idea to keep a reference to the color
        // specified in setPaint() or setColor(), rather than creating a
        // new object every time getPaint() is called.
        return SWTUtils.toAwtColor(this.gc.getForeground());
    }

    /**
     * Sets the paint for this graphics context.  For now, this graphics
     * context only supports instances of {@link Color} or
     * {@link GradientPaint} (in the latter case there is no real gradient
     * support, the paint used is the <code>Color</code> returned by
     * <code>getColor1()</code>).
     *
     * @param paint  the paint (<code>null</code> not permitted).
     *
     * @see #getPaint()
     * @see #setColor(Color)
     */
    public void setPaint(Paint paint) {
        if (paint instanceof Color) {
            setColor((Color) paint);
        }
        else if (paint instanceof GradientPaint) {
            GradientPaint gp = (GradientPaint) paint;
            setColor(gp.getColor1());
        }
        else {
            throw new RuntimeException("Can only handle 'Color' at present.");
        }
    }

    /**
     * Returns the current color for this graphics context.
     *
     * @return The current color.
     *
     * @see #setColor(Color)
     */
    public Color getColor() {
        // TODO: it might be a good idea to keep a reference to the color
        // specified in setPaint() or setColor(), rather than creating a
        // new object every time getPaint() is called.
        return SWTUtils.toAwtColor(this.gc.getForeground());
    }

    /**
     * Sets the current color for this graphics context.
     *
     * @param color  the color.
     *
     * @see #getColor()
     */
    public void setColor(Color color) {
        org.eclipse.swt.graphics.Color swtColor = getSwtColorFromPool(color);
        this.gc.setForeground(swtColor);
        // handle transparency and compositing.
        if (this.composite instanceof AlphaComposite) {
            AlphaComposite acomp = (AlphaComposite) this.composite;
            switch (acomp.getRule()) {
            case AlphaComposite.SRC_OVER:
                this.gc.setAlpha((int) (color.getAlpha() * acomp.getAlpha()));
                break;
            default:
                this.gc.setAlpha(color.getAlpha());
                break;
            }
        }
    }

    /**
     * Sets the background colour.
     *
     * @param color  the colour.
     */
    public void setBackground(Color color) {
        org.eclipse.swt.graphics.Color swtColor = getSwtColorFromPool(color);
        this.gc.setBackground(swtColor);
    }

    /**
     * Returns the background colour.
     *
     * @return The background colour.
     */
    public Color getBackground() {
        return SWTUtils.toAwtColor(this.gc.getBackground());
    }

    /**
     * Not implemented - see {@link Graphics#setPaintMode()}.
     */
    public void setPaintMode() {
        // TODO Auto-generated method stub
    }

    /**
     * Not implemented - see {@link Graphics#setXORMode(Color)}.
     *
     * @param color  the colour.
     */
    public void setXORMode(Color color) {
        // TODO Auto-generated method stub
    }

    /**
     * Returns the current composite.
     *
     * @return The current composite.
     *
     * @see #setComposite(Composite)
     */
    public Composite getComposite() {
        return this.composite;
    }

    /**
     * Sets the current composite.  This implementation currently supports
     * only the {@link AlphaComposite} class.
     *
     * @param comp  the composite.
     */
    public void setComposite(Composite comp) {
        this.composite = comp;
        if (comp instanceof AlphaComposite) {
            AlphaComposite acomp = (AlphaComposite) comp;
            int alpha = (int) (acomp.getAlpha() * 0xFF);
            this.gc.setAlpha(alpha);
        }
        else {
            System.out.println("warning, can only handle alpha composite at the moment.");
        }
    }

    /**
     * Returns the current stroke for this graphics context.
     *
     * @return The current stroke.
     *
     * @see #setStroke(Stroke)
     */
    public Stroke getStroke() {
        return new BasicStroke(this.gc.getLineWidth(), this.gc.getLineCap(),
                this.gc.getLineJoin());
    }

    /**
     * Sets the stroke for this graphics context.  For now, this implementation
     * only recognises the {@link BasicStroke} class.
     *
     * @param stroke  the stroke (<code>null</code> not permitted).
     *
     * @see #getStroke()
     */
    public void setStroke(Stroke stroke) {
        if (stroke instanceof BasicStroke) {
            BasicStroke bs = (BasicStroke) stroke;
            // linewidth
            this.gc.setLineWidth((int) bs.getLineWidth());

            // line join
            switch (bs.getLineJoin()) {
                case BasicStroke.JOIN_BEVEL :
                    this.gc.setLineJoin(SWT.JOIN_BEVEL);
                    break;
                case BasicStroke.JOIN_MITER :
                    this.gc.setLineJoin(SWT.JOIN_MITER);
                    break;
                case BasicStroke.JOIN_ROUND :
                    this.gc.setLineJoin(SWT.JOIN_ROUND);
                    break;
            }

            // line cap
            switch (bs.getEndCap()) {
                case BasicStroke.CAP_BUTT :
                    this.gc.setLineCap(SWT.CAP_FLAT);
                    break;
                case BasicStroke.CAP_ROUND :
                    this.gc.setLineCap(SWT.CAP_ROUND);
                    break;
                case BasicStroke.CAP_SQUARE :
                    this.gc.setLineCap(SWT.CAP_SQUARE);
                    break;
            }

            // set the line style to solid by default
            this.gc.setLineStyle(SWT.LINE_SOLID);

            // apply dash style if any
            float[] dashes = bs.getDashArray();
            if (dashes != null) {
                int[] swtDashes = new int[dashes.length];
                for (int i = 0; i < swtDashes.length; i++) {
                    swtDashes[i] = (int) dashes[i];
                }
                this.gc.setLineDash(swtDashes);
            }
        }
        else {
            throw new RuntimeException(
                    "Can only handle 'Basic Stroke' at present.");
        }
    }

    /**
     * Applies the specified clip.
     *
     * @param s  the shape for the clip.
     */
    public void clip(Shape s) {
        Path path = toSwtPath(s);
        this.gc.setClipping(path);
        path.dispose();
    }

    /**
     * Returns the clip bounds.
     *
     * @return The clip bounds.
     */
    public Rectangle getClipBounds() {
        org.eclipse.swt.graphics.Rectangle clip = this.gc.getClipping();
        return new Rectangle(clip.x, clip.y, clip.width, clip.height);
    }

    /**
     * Sets the clipping to the intersection of the current clip region and
     * the specified rectangle.
     *
     * @param x  the x-coordinate.
     * @param y  the y-coordinate.
     * @param width  the width.
     * @param height  the height.
     */
    public void clipRect(int x, int y, int width, int height) {
        org.eclipse.swt.graphics.Rectangle clip = this.gc.getClipping();
        clip.intersects(x, y, width, height);
        this.gc.setClipping(clip);
    }

    /**
     * Returns the current clip.
     *
     * @return The current clip.
     */
    public Shape getClip() {
        return SWTUtils.toAwtRectangle(this.gc.getClipping());
    }

    /**
     * Sets the clip region.
     *
     * @param clip  the clip.
     */
    public void setClip(Shape clip) {
        if (clip == null) {
            return;
        }
        Path clipPath = toSwtPath(clip);
        this.gc.setClipping(clipPath);
        clipPath.dispose();
    }

    /**
     * Sets the clip region to the specified rectangle.
     *
     * @param x  the x-coordinate.
     * @param y  the y-coordinate.
     * @param width  the width.
     * @param height  the height.
     */
    public void setClip(int x, int y, int width, int height) {
        this.gc.setClipping(x, y, width, height);
    }

    /**
     * Returns the current transform.
     *
     * @return The current transform.
     */
    public AffineTransform getTransform() {
        Transform swtTransform = new Transform(this.gc.getDevice());
        this.gc.getTransform(swtTransform);
        AffineTransform awtTransform = toAwtTransform(swtTransform);
        swtTransform.dispose();
        return awtTransform;
    }

    /**
     * Sets the current transform.
     *
     * @param t  the transform.
     */
    public void setTransform(AffineTransform t) {
        Transform transform = getSwtTransformFromPool(t);
        this.gc.setTransform(transform);
    }

    /**
     * Concatenates the specified transform to the existing transform.
     *
     * @param t  the transform.
     */
    public void transform(AffineTransform t) {
        Transform swtTransform = new Transform(this.gc.getDevice());
        this.gc.getTransform(swtTransform);
        swtTransform.multiply(getSwtTransformFromPool(t));
        this.gc.setTransform(swtTransform);
        swtTransform.dispose();
    }

    /**
     * Applies a translation.
     *
     * @param x  the translation along the x-axis.
     * @param y  the translation along the y-axis.
     */
    public void translate(int x, int y) {
        Transform swtTransform = new Transform(this.gc.getDevice());
        this.gc.getTransform(swtTransform);
        swtTransform.translate(x, y);
        this.gc.setTransform(swtTransform);
        swtTransform.dispose();
    }

    /**
     * Applies a translation.
     *
     * @param tx  the translation along the x-axis.
     * @param ty  the translation along the y-axis.
     */
    public void translate(double tx, double ty) {
        translate((int) tx, (int) ty);
    }

    /**
     * Applies a rotation transform.
     *
     * @param theta  the angle of rotation.
     */
    public void rotate(double theta) {
        Transform swtTransform = new Transform(this.gc.getDevice());
        this.gc.getTransform(swtTransform);
        swtTransform.rotate((float) (theta * 180 / Math.PI));
        this.gc.setTransform(swtTransform);
        swtTransform.dispose();
    }

    /**
     * Not implemented - see {@link Graphics2D#rotate(double, double, double)}.
     *
     * @see java.awt.Graphics2D#rotate(double, double, double)
     */
    public void rotate(double theta, double x, double y) {
        // TODO Auto-generated method stub
    }

    /**
     * Applies a scale transform.
     *
     * @param scaleX  the scale factor along the x-axis.
     * @param scaleY  the scale factor along the y-axis.
     */
    public void scale(double scaleX, double scaleY) {
        Transform swtTransform = new Transform(this.gc.getDevice());
        this.gc.getTransform(swtTransform);
        swtTransform.scale((float) scaleX, (float) scaleY);
        this.gc.setTransform(swtTransform);
        swtTransform.dispose();
    }

    /**
     * Applies a shear transform.
     *
     * @param shearX  the x-factor.
     * @param shearY  the y-factor.
     */
    public void shear(double shearX, double shearY) {
        Transform swtTransform = new Transform(this.gc.getDevice());
        this.gc.getTransform(swtTransform);
        Transform shear = new Transform(this.gc.getDevice(), 1f, (float) shearX,
                (float) shearY, 1f, 0, 0);
        swtTransform.multiply(shear);
        this.gc.setTransform(swtTransform);
        swtTransform.dispose();
    }

    /**
     * Draws the outline of the specified shape using the current stroke and
     * paint settings.
     *
     * @param shape  the shape (<code>null</code> not permitted).
     *
     * @see #getPaint()
     * @see #getStroke()
     * @see #fill(Shape)
     */
    public void draw(Shape shape) {
        Path path = toSwtPath(shape);
        this.gc.drawPath(path);
        path.dispose();
    }

    /**
     * Draws a line from (x1, y1) to (x2, y2) using the current stroke
     * and paint settings.
     *
     * @param x1  the x-coordinate for the starting point.
     * @param y1  the y-coordinate for the starting point.
     * @param x2  the x-coordinate for the ending point.
     * @param y2  the y-coordinate for the ending point.
     *
     * @see #draw(Shape)
     */
    public void drawLine(int x1, int y1, int x2, int y2) {
        this.gc.drawLine(x1, y1, x2, y2);
    }

    /**
     * Draws the outline of the polygon specified by the given points, using
     * the current paint and stroke settings.
     *
     * @param xPoints  the x-coordinates.
     * @param yPoints  the y-coordinates.
     * @param npoints  the number of points in the polygon.
     *
     * @see #draw(Shape)
     */
    public void drawPolygon(int [] xPoints, int [] yPoints, int npoints) {
        drawPolyline(xPoints, yPoints, npoints);
        if (npoints > 1) {
            this.gc.drawLine(xPoints[npoints - 1], yPoints[npoints - 1],
                    xPoints[0], yPoints[0]);
        }
    }

    /**
     * Draws a sequence of connected lines specified by the given points, using
     * the current paint and stroke settings.
     *
     * @param xPoints  the x-coordinates.
     * @param yPoints  the y-coordinates.
     * @param npoints  the number of points in the polygon.
     *
     * @see #draw(Shape)
     */
    public void drawPolyline(int [] xPoints, int [] yPoints, int npoints) {
        if (npoints > 1) {
            int x0 = xPoints[0];
            int y0 = yPoints[0];
            int x1 = 0, y1 = 0;
            for (int i = 1; i < npoints; i++) {
                x1 = xPoints[i];
                y1 = yPoints[i];
                this.gc.drawLine(x0, y0, x1, y1);
                x0 = x1;
                y0 = y1;
            }
        }
    }

    /**
     * Draws an oval that fits within the specified rectangular region.
     *
     * @param x  the x-coordinate.
     * @param y  the y-coordinate.
     * @param width  the frame width.
     * @param height  the frame height.
     *
     * @see #fillOval(int, int, int, int)
     * @see #draw(Shape)
     */
    public void drawOval(int x, int y, int width, int height) {
        this.gc.drawOval(x, y, width - 1, height - 1);
    }

    /**
     * Draws an arc that is part of an ellipse that fits within the specified
     * framing rectangle.
     *
     * @param x  the x-coordinate.
     * @param y  the y-coordinate.
     * @param width  the frame width.
     * @param height  the frame height.
     * @param arcStart  the arc starting point, in degrees.
     * @param arcAngle  the extent of the arc.
     *
     * @see #fillArc(int, int, int, int, int, int)
     */
    public void drawArc(int x, int y, int width, int height, int arcStart,
            int arcAngle) {
        this.gc.drawArc(x, y, width - 1, height - 1, arcStart, arcAngle);
    }

    /**
     * Draws a rectangle with rounded corners that fits within the specified
     * framing rectangle.
     *
     * @param x  the x-coordinate.
     * @param y  the y-coordinate.
     * @param width  the frame width.
     * @param height  the frame height.
     * @param arcWidth  the width of the arc defining the roundedness of the
     *         rectangle's corners.
     * @param arcHeight the height of the arc defining the roundedness of the
     *         rectangle's corners.
     *
     * @see #fillRoundRect(int, int, int, int, int, int)
     */
    public void drawRoundRect(int x, int y, int width, int height,
            int arcWidth, int arcHeight) {
        this.gc.drawRoundRectangle(x, y, width - 1, height - 1, arcWidth,
                arcHeight);
    }

    /**
     * Fills the specified shape using the current paint.
     *
     * @param shape  the shape (<code>null</code> not permitted).
     *
     * @see #getPaint()
     * @see #draw(Shape)
     */
    public void fill(Shape shape) {
        Path path = toSwtPath(shape);
        // Note that for consistency with the AWT implementation, it is
        // necessary to switch temporarily the foreground and background
        // colours
        switchColors();
        this.gc.fillPath(path);
        switchColors();
        path.dispose();
    }

    /**
     * Fill a rectangle area on the swt graphic composite.
     * The <code>fillRectangle</code> method of the <code>GC</code>
     * class uses the background color so we must switch colors.
     * @see java.awt.Graphics#fillRect(int, int, int, int)
     */
    public void fillRect(int x, int y, int width, int height) {
        this.switchColors();
        this.gc.fillRectangle(x, y, width, height);
        this.switchColors();
    }

    /**
     * Fills the specified rectangle with the current background colour.
     *
     * @param x  the x-coordinate for the rectangle.
     * @param y  the y-coordinate for the rectangle.
     * @param width  the width.
     * @param height  the height.
     *
     * @see #fillRect(int, int, int, int)
     */
    public void clearRect(int x, int y, int width, int height) {
        Paint saved = getPaint();
        setPaint(getBackground());
        fillRect(x, y, width, height);
        setPaint(saved);
    }

    /**
     * Fills the specified polygon.
     *
     * @param xPoints  the x-coordinates.
     * @param yPoints  the y-coordinates.
     * @param npoints  the number of points.
     */
    public void fillPolygon(int[] xPoints, int[] yPoints, int npoints) {
        int[] pointArray = new int[npoints * 2];
        for (int i = 0; i < npoints; i++) {
            pointArray[2 * i] = xPoints[i];
            pointArray[2 * i + 1] = yPoints[i];
        }
        switchColors();
        this.gc.fillPolygon(pointArray);
        switchColors();
    }

    /**
     * Draws a rectangle with rounded corners that fits within the specified
     * framing rectangle.
     *
     * @param x  the x-coordinate.
     * @param y  the y-coordinate.
     * @param width  the frame width.
     * @param height  the frame height.
     * @param arcWidth  the width of the arc defining the roundedness of the
     *         rectangle's corners.
     * @param arcHeight the height of the arc defining the roundedness of the
     *         rectangle's corners.
     *
     * @see #drawRoundRect(int, int, int, int, int, int)
     */
    public void fillRoundRect(int x, int y, int width, int height,
            int arcWidth, int arcHeight) {
        switchColors();
        this.gc.fillRoundRectangle(x, y, width - 1, height - 1, arcWidth,
                arcHeight);
        switchColors();
    }

    /**
     * Fills an oval that fits within the specified rectangular region.
     *
     * @param x  the x-coordinate.
     * @param y  the y-coordinate.
     * @param width  the frame width.
     * @param height  the frame height.
     *
     * @see #drawOval(int, int, int, int)
     * @see #fill(Shape)
     */
    public void fillOval(int x, int y, int width, int height) {
        switchColors();
        this.gc.fillOval(x, y, width - 1, height - 1);
        switchColors();
    }

    /**
     * Fills an arc that is part of an ellipse that fits within the specified
     * framing rectangle.
     *
     * @param x  the x-coordinate.
     * @param y  the y-coordinate.
     * @param width  the frame width.
     * @param height  the frame height.
     * @param arcStart  the arc starting point, in degrees.
     * @param arcAngle  the extent of the arc.
     *
     * @see #drawArc(int, int, int, int, int, int)
     */
    public void fillArc(int x, int y, int width, int height, int arcStart,
            int arcAngle) {
        switchColors();
        this.gc.fillArc(x, y, width - 1, height - 1, arcStart, arcAngle);
        switchColors();
    }

    /**
     * Returns the font in form of an awt font created
     * with the parameters of the font of the swt graphic
     * composite.
     * @see java.awt.Graphics#getFont()
     */
    public Font getFont() {
        // retrieve the swt font description in an os indept way
        FontData[] fontData = this.gc.getFont().getFontData();
        // create a new awt font with the appropiate data
        return SWTUtils.toAwtFont(this.gc.getDevice(), fontData[0], true);
    }

    /**
     * Set the font swt graphic composite from the specified
     * awt font. Be careful that the newly created swt font
     * must be disposed separately.
     * @see java.awt.Graphics#setFont(java.awt.Font)
     */
    public void setFont(Font font) {
        org.eclipse.swt.graphics.Font swtFont = getSwtFontFromPool(font);
        this.gc.setFont(swtFont);
    }

    /**
     * Returns the font metrics.
     *
     * @param font the font.
     *
     * @return The font metrics.
     */
    public FontMetrics getFontMetrics(Font font) {
        return SWTUtils.DUMMY_PANEL.getFontMetrics(font);
    }

    /**
     * Returns the font render context.
     *
     * @return The font render context.
     */
    public FontRenderContext getFontRenderContext() {
        FontRenderContext fontRenderContext = new FontRenderContext(
                new AffineTransform(), true, true);
        return fontRenderContext;
    }

    /**
     * Not implemented - see {@link Graphics2D#drawGlyphVector(GlyphVector,
     * float, float)}.
     */
    public void drawGlyphVector(GlyphVector g, float x, float y) {
        // TODO Auto-generated method stub

    }

    /**
     * Draws a string on the receiver. note that
     * to be consistent with the awt method,
     * the y has to be modified with the ascent of the font.
     *
     * @see java.awt.Graphics#drawString(java.lang.String, int, int)
     */
    public void drawString(String text, int x, int y) {
        float fm = this.gc.getFontMetrics().getAscent();
        this.gc.drawString(text, x, (int) (y - fm), true);
    }

    /**
     * Draws a string at the specified position.
     *
     * @param text  the string.
     * @param x  the x-coordinate.
     * @param y  the y-coordinate.
     */
    public void drawString(String text, float x, float y) {
        float fm = this.gc.getFontMetrics().getAscent();
        this.gc.drawString(text, (int) x, (int) (y - fm), true);
    }

    /**
     * Draws a string at the specified position.
     *
     * @param iterator  the string.
     * @param x  the x-coordinate.
     * @param y  the y-coordinate.
     */
    public void drawString(AttributedCharacterIterator iterator, int x, int y) {
        // TODO Auto-generated method stub
    }

    /**
     * Draws a string at the specified position.
     *
     * @param iterator  the string.
     * @param x  the x-coordinate.
     * @param y  the y-coordinate.
     */
    public void drawString(AttributedCharacterIterator iterator, float x,
            float y) {
        // TODO Auto-generated method stub
    }

    /**
     * Not implemented - see {@link Graphics2D#hit(Rectangle, Shape, boolean)}.
     *
     * @return <code>false</code>.
     */
    public boolean hit(Rectangle rect, Shape text, boolean onStroke) {
        // TODO Auto-generated method stub
        return false;
    }

    /**
     * Not implemented - see {@link Graphics#copyArea(int, int, int, int, int,
     * int)}.
     */
    public void copyArea(int x, int y, int width, int height, int dx, int dy) {
        // TODO Auto-generated method stub
    }

    /**
     * Not implemented - see {@link Graphics2D#drawImage(Image,
     * AffineTransform, ImageObserver)}.
     *
     * @param image  the image.
     * @param xform  the transform.
     * @param obs  an image observer.
     *
     * @return A boolean.
     */
    public boolean drawImage(Image image, AffineTransform xform,
            ImageObserver obs) {
        // TODO Auto-generated method stub
        return false;
    }

    /**
     * Draws an image.
     *
     * @param image  the image.
     * @param op  the image operation.
     * @param x  the x-coordinate.
     * @param y  the y-coordinate.
     */
    public void drawImage(BufferedImage image, BufferedImageOp op, int x,
            int y) {
        org.eclipse.swt.graphics.Image im = new org.eclipse.swt.graphics.Image(
                this.gc.getDevice(), SWTUtils.convertToSWT(image));
        this.gc.drawImage(im, x, y);
        im.dispose();
    }

    /**
     * Draws an SWT image with the top left corner of the image aligned to the
     * point (x, y).
     *
     * @param image  the image.
     * @param x  the x-coordinate.
     * @param y  the y-coordinate.
     */
    public void drawImage(org.eclipse.swt.graphics.Image image, int x, int y) {
        this.gc.drawImage(image, x, y);
    }

    /**
     * Not implemented - see {@link Graphics2D#drawRenderedImage(RenderedImage,
     * AffineTransform)}.
     *
     * @param image  the image.
     * @param xform  the transform.
     */
    public void drawRenderedImage(RenderedImage image, AffineTransform xform) {
        // TODO Auto-generated method stub
    }

    /**
     * Not implemented - see {@link Graphics2D#drawRenderableImage(
     * RenderableImage, AffineTransform)}.
     *
     * @param image  the image.
     * @param xform  the transform.
     */
    public void drawRenderableImage(RenderableImage image,
            AffineTransform xform) {
        // TODO Auto-generated method stub

    }

    /**
     * Draws an image with the top left corner aligned to the point (x, y).
     *
     * @param image  the image.
     * @param x  the x-coordinate.
     * @param y  the y-coordinate.
     * @param observer  ignored here.
     *
     * @return <code>true</code> if the image has been drawn.
     */
    public boolean drawImage(Image image, int x, int y,
            ImageObserver observer) {
        ImageData data = SWTUtils.convertAWTImageToSWT(image);
        if (data == null) {
            return false;
        }
        org.eclipse.swt.graphics.Image im = new org.eclipse.swt.graphics.Image(
                this.gc.getDevice(), data);
        this.gc.drawImage(im, x, y);
        im.dispose();
        return true;
    }

    /**
     * Draws an image with the top left corner aligned to the point (x, y),
     * and scaled to the specified width and height.
     *
     * @param image  the image.
     * @param x  the x-coordinate.
     * @param y  the y-coordinate.
     * @param width  the width for the rendered image.
     * @param height  the height for the rendered image.
     * @param observer  ignored here.
     *
     * @return <code>true</code> if the image has been drawn.
     */
    public boolean drawImage(Image image, int x, int y, int width, int height,
            ImageObserver observer) {
        ImageData data = SWTUtils.convertAWTImageToSWT(image);
        if (data == null) {
            return false;
        }
        org.eclipse.swt.graphics.Image im = new org.eclipse.swt.graphics.Image(
                this.gc.getDevice(), data);
        org.eclipse.swt.graphics.Rectangle bounds = im.getBounds();
        this.gc.drawImage(im, 0, 0, bounds.width, bounds.height, x, y, width,
                height);
        im.dispose();
        return true;
    }

    /**
     * Draws an image.
     *
     * @param image (<code>null</code> not permitted).
     * @param x  the x-coordinate.
     * @param y  the y-coordinate.
     * @param bgcolor  the background color.
     * @param observer  an image observer.
     *
     * @return A boolean.
     */
    public boolean drawImage(Image image, int x, int y, Color bgcolor,
            ImageObserver observer) {
        if (image == null) {
            throw new IllegalArgumentException("Null 'image' argument.");
        }
        int w = image.getWidth(null);
        int h = image.getHeight(null);
        if (w == -1 || h == -1) {
            return false;
        }
        Paint savedPaint = getPaint();
        fill(new Rectangle2D.Double(x, y, w, h));
        setPaint(savedPaint);
        return drawImage(image, x, y, observer);
    }

    /**
     * Draws an image.
     *
     * @param image  the image (<code>null</code> not permitted).
     * @param x  the x-coordinate.
     * @param y  the y-coordinate.
     * @param width  the width.
     * @param height  the height.
     * @param bgcolor  the background colour.
     * @param observer  an image observer.
     *
     * @return A boolean.
     */
    public boolean drawImage(Image image, int x, int y, int width, int height,
            Color bgcolor, ImageObserver observer) {
        if (image == null) {
            throw new IllegalArgumentException("Null 'image' argument.");
        }
        int w = image.getWidth(null);
        int h = image.getHeight(null);
        if (w == -1 || h == -1) {
            return false;
        }
        Paint savedPaint = getPaint();
        fill(new Rectangle2D.Double(x, y, w, h));
        setPaint(savedPaint);
        return drawImage(image, x, y, width, height, observer);
    }

    /**
     * Not implemented - see {@link Graphics#drawImage(Image, int, int, int,
     *     int, int, int, int, int, ImageObserver)}.
     *
     * @param image  the image.
     * @param dx1
     * @param dy1
     * @param dx2
     * @param dy2
     * @param sx1
     * @param sy1
     * @param sx2
     * @param sy2
     * @param observer
     */
    public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2,
            int sx1, int sy1, int sx2, int sy2, ImageObserver observer) {
        // TODO Auto-generated method stub
        return false;
    }

    /**
     * Not implemented - see {@link Graphics#drawImage(Image, int, int, int,
     *     int, int, int, int, int, Color, ImageObserver)}.
     *
     * @param image  the image.
     * @param dx1
     * @param dy1
     * @param dx2
     * @param dy2
     * @param sx1
     * @param sy1
     * @param sx2
     * @param sy2
     * @param bgcolor
     * @param observer
     */
    public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2,
            int sx1, int sy1, int sx2, int sy2, Color bgcolor,
            ImageObserver observer) {
        // TODO Auto-generated method stub
        return false;
    }

    /**
     * Releases resources held by this instance (but note that the caller
     * must dispose of the 'GC' passed to the constructor).
     *
     * @see java.awt.Graphics#dispose()
     */
    public void dispose() {
        // we dispose resources we own but user must dispose gc
        disposeResourcePool();
    }

    /**
     * Add given swt resource to the resource pool. All resources added
     * to the resource pool will be disposed when {@link #dispose()} is called.
     *
     * @param resource the resource to add to the pool.
     * @return the swt <code>Resource</code> just added.
     */
    private Resource addToResourcePool(Resource resource) {
        this.resourcePool.add(resource);
        return resource;
    }

    /**
     * Dispose the resource pool.
     */
    private void disposeResourcePool() {
        for (Iterator it = this.resourcePool.iterator(); it.hasNext();) {
            Resource resource = (Resource) it.next();
            resource.dispose();
        }
        this.fontsPool.clear();
        this.colorsPool.clear();
        this.transformsPool.clear();
        this.resourcePool.clear();
    }

    /**
     * Internal method to convert a AWT font object into
     * a SWT font resource. If a corresponding SWT font
     * instance is already in the pool, it will be used
     * instead of creating a new one. This is used in
     * {@link #setFont()} for instance.
     *
     * @param font The AWT font to convert.
     * @return The SWT font instance.
     */
    private org.eclipse.swt.graphics.Font getSwtFontFromPool(Font font) {
        org.eclipse.swt.graphics.Font swtFont = (org.eclipse.swt.graphics.Font)
        this.fontsPool.get(font);
        if (swtFont == null) {
            swtFont = new org.eclipse.swt.graphics.Font(this.gc.getDevice(),
                    SWTUtils.toSwtFontData(this.gc.getDevice(), font, true));
            addToResourcePool(swtFont);
            this.fontsPool.put(font, swtFont);
        }
        return swtFont;
    }

    /**
     * Internal method to convert a AWT color object into
     * a SWT color resource. If a corresponding SWT color
     * instance is already in the pool, it will be used
     * instead of creating a new one. This is used in
     * {@link #setColor()} for instance.
     *
     * @param awtColor The AWT color to convert.
     * @return A SWT color instance.
     */
    private org.eclipse.swt.graphics.Color getSwtColorFromPool(Color awtColor) {
        org.eclipse.swt.graphics.Color swtColor =
                (org.eclipse.swt.graphics.Color)
                // we can't use the following valueOf() method, because it
                // won't compile with JDK1.4
                // this.colorsPool.get(Integer.valueOf(awtColor.getRGB()));
                this.colorsPool.get(new Integer(awtColor.getRGB()));
        if (swtColor == null) {
            swtColor = SWTUtils.toSwtColor(this.gc.getDevice(), awtColor);
            addToResourcePool(swtColor);
            // see comment above
            //this.colorsPool.put(Integer.valueOf(awtColor.getRGB()), swtColor);
            this.colorsPool.put(new Integer(awtColor.getRGB()), swtColor);
        }
        return swtColor;
    }

    /**
     * Internal method to convert a AWT transform object into
     * a SWT transform resource. If a corresponding SWT transform
     * instance is already in the pool, it will be used
     * instead of creating a new one. This is used in
     * {@link #setTransform()} for instance.
     *
     * @param awtTransform The AWT transform to convert.
     * @return A SWT transform instance.
     */
    private Transform getSwtTransformFromPool(AffineTransform awtTransform) {
        Transform t = (Transform) this.transformsPool.get(awtTransform);
        if (t == null) {
            t = new Transform(this.gc.getDevice());
            double[] matrix = new double[6];
            awtTransform.getMatrix(matrix);
            t.setElements((float) matrix[0], (float) matrix[1],
                    (float) matrix[2], (float) matrix[3],
                    (float) matrix[4], (float) matrix[5]);
            addToResourcePool(t);
            this.transformsPool.put(awtTransform, t);
        }
        return t;
    }

    /**
     * Perform a switch between foreground and background
     * color of gc. This is needed for consistency with
     * the awt behaviour, and is required notably for the
     * filling methods.
     */
    private void switchColors() {
        org.eclipse.swt.graphics.Color bg = this.gc.getBackground();
        org.eclipse.swt.graphics.Color fg = this.gc.getForeground();
        this.gc.setBackground(fg);
        this.gc.setForeground(bg);
    }

    /**
     * Converts an AWT <code>Shape</code> into a SWT <code>Path</code>.
     *
     * @param shape  the shape (<code>null</code> not permitted).
     *
     * @return The path.
     */
    private Path toSwtPath(Shape shape) {
        int type;
        float[] coords = new float[6];
        Path path = new Path(this.gc.getDevice());
        PathIterator pit = shape.getPathIterator(null);
        while (!pit.isDone()) {
            type = pit.currentSegment(coords);
            switch (type) {
                case (PathIterator.SEG_MOVETO):
                    path.moveTo(coords[0], coords[1]);
                    break;
                case (PathIterator.SEG_LINETO):
                    path.lineTo(coords[0], coords[1]);
                    break;
                case (PathIterator.SEG_QUADTO):
                    path.quadTo(coords[0], coords[1], coords[2], coords[3]);
                    break;
                case (PathIterator.SEG_CUBICTO):
                    path.cubicTo(coords[0], coords[1], coords[2],
                            coords[3], coords[4], coords[5]);
                    break;
                case (PathIterator.SEG_CLOSE):
                    path.close();
                    break;
                default:
                    break;
            }
            pit.next();
        }
        return path;
    }

    /**
     * Converts an SWT transform into the equivalent AWT transform.
     *
     * @param swtTransform  the SWT transform.
     *
     * @return The AWT transform.
     */
    private AffineTransform toAwtTransform(Transform swtTransform) {
        float[] elements = new float[6];
        swtTransform.getElements(elements);
        AffineTransform awtTransform = new AffineTransform(elements);
        return awtTransform;
    }

}








17.118.SWT AWT Swing
17.118.1.Embeded Swing/AWT components to SWTEmbeded Swing/AWT components to SWT
17.118.2.Using AWT to paint inside SWTUsing AWT to paint inside SWT
17.118.3.Embed a JTable in SWT (no flicker)Embed a JTable in SWT (no flicker)
17.118.4.Create a FontData object which encapsulate the essential data to create a swt font.
17.118.5.Create an awt font by converting as much information as possible from the provided swt Font.
17.118.6.Create an awt font by converting as much information as possible from the provided swt FontData.
17.118.7.Creates a swt color instance to match the rgb values of the specified awt color. alpha channel is not supported.
17.118.8.Creates a swt color instance to match the rgb values of the specified awt paint.
17.118.9.Creates an AWT MouseEvent from a swt event.
17.118.10.Creates an awt color instance to match the rgb values of the specified swt color.
17.118.11.Draw Graphics2D stuff on a swt composite
17.118.12.Returns an AWT point with the same coordinates as the specified SWT point.
17.118.13.Returns an SWT point with the same coordinates as the specified AWT point (rounded to integer values).
17.118.14.Returns an SWT point with the same coordinates as the specified AWT point.
17.118.15.Transform a swt Rectangle instance into an AWT Rectangle.
17.118.16.Transform an awt Rectangle2d instance into a swt Rectangle2d.