diff --git a/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTImage.java b/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTImage.java index 735079b..6e0674f 100644 --- a/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTImage.java +++ b/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTImage.java @@ -39,115 +39,136 @@ import edu.umd.cs.piccolo.util.PPaintContext; /** - * PImage is a wrapper around a java.awt.Image. If this node is copied or - * serialized that image will be converted into a BufferedImage if it is not - * already one. - *
+ * PSWTImage is a wrapper around a org.eclipse.swt.graphics.Image. * * @version 1.0 * @author Jesse Grosjean */ public class PSWTImage extends PNode { + private static final long serialVersionUID = 1L; - /** - * - */ - private static final long serialVersionUID = 1L; + private transient final PSWTCanvas canvas; - private transient final PSWTCanvas canvas; + private transient Image image; - private transient Image image; + /** + * Constructs a PSWTImage attached to the provided canvas and with a null + * image. + * + * The developer will need to call setImage for this node to be useful. + * + * TODO: determine if canvas is actually necessary + * + * @param canvas + * canvas to associate with the image node + */ + public PSWTImage(final PSWTCanvas canvas) { + this.canvas = canvas; + canvas.addDisposeListener(new DisposeListener() { + public void widgetDisposed(final DisposeEvent de) { + disposeImage(); + } + }); + } - public PSWTImage(final PSWTCanvas canvas) { - super(); + /** + * Constructs a PSWTImage wrapping the provided image. + * + * @param canvas + * canvas to associate with the image node + * @param image + * image to be wrapped by this PSWTImage + */ + public PSWTImage(final PSWTCanvas canvas, final Image image) { + this(canvas); + setImage(image); + } - this.canvas = canvas; - canvas.addDisposeListener(new DisposeListener() { - public void widgetDisposed(final DisposeEvent de) { - disposeImage(); - } - }); - } + /** + * Constructs a PSWTImage wrapping the provided image after loading it from + * the file. + * + * @param canvas + * canvas to associate with the image node + * @param fileName + * path to the image, will be loaded and converted to an Image + * internally + */ + public PSWTImage(final PSWTCanvas canvas, final String fileName) { + this(canvas); + setImage(fileName); + } - public PSWTImage(final PSWTCanvas canvas, final Image newImage) { - this(canvas); - setImage(newImage); - } + /** + * Returns the image that is shown by this node, may be null. + * + * @return the image that is shown by this node + */ + public Image getImage() { + return image; + } - public PSWTImage(final PSWTCanvas canvas, final String fileName) { - this(canvas); - setImage(fileName); - } + /** + * Set the image that is wrapped by this PImage node. This method will also + * load the image using a MediaTracker before returning. And if the this + * PImage is accelerated that image will be copied into an accelerated image + * if needed. Note that this may cause undesired results with images that + * have transparent regions, for those cases you may want to set the PImage + * to be not accelerated. + */ + public void setImage(final String fileName) { + setImage(new Image(canvas.getDisplay(), fileName)); + } - /** - * Returns the image that is shown by this node. - * - * @return the image that is shown by this node - */ - public Image getImage() { - return image; - } + /** + * Set the image that is wrapped by this PImage node. This method will also + * load the image using a MediaTracker before returning. And if the this + * PImage is accelerated that I'm will be copied into an accelerated image + * if needed. Note that this may cause undesired results with images that + * have transparent regions, for those cases you may want to set the PImage + * to be not accelerated. + */ + public void setImage(final Image newImage) { + final Image old = image; + image = newImage; - /** - * Set the image that is wrapped by this PImage node. This method will also - * load the image using a MediaTracker before returning. And if the this - * PImage is accelerated that I'm will be copied into an accelerated image - * if needed. Note that this may cause undesired results with images that - * have transparent regions, for those cases you may want to set the PImage - * to be not accelerated. - */ - public void setImage(final String fileName) { - setImage(new Image(canvas.getDisplay(), fileName)); - } + if (image != null) { + final Rectangle bounds = getImage().getBounds(); + setBounds(0, 0, bounds.width, bounds.height); + invalidatePaint(); + } - /** - * Set the image that is wrapped by this PImage node. This method will also - * load the image using a MediaTracker before returning. And if the this - * PImage is accelerated that I'm will be copied into an accelerated image - * if needed. Note that this may cause undesired results with images that - * have transparent regions, for those cases you may want to set the PImage - * to be not accelerated. - */ - public void setImage(final Image newImage) { - final Image old = image; - image = newImage; + firePropertyChange(PImage.PROPERTY_CODE_IMAGE, PImage.PROPERTY_IMAGE, + old, image); + } - if (image != null) { - final Rectangle bounds = getImage().getBounds(); - setBounds(0, 0, bounds.width, bounds.height); - invalidatePaint(); - } - else { - image = null; - } + /** + * Subclasses may override this method to provide different image dispose + * behavior. + */ + protected void disposeImage() { + if (image != null) { + image.dispose(); + } + } - firePropertyChange(PImage.PROPERTY_CODE_IMAGE, PImage.PROPERTY_IMAGE, old, image); - } + /** {@inheritDoc} */ + protected void paint(final PPaintContext paintContext) { + if (getImage() != null) { + final Rectangle r = image.getBounds(); + final PBounds b = getBoundsReference(); + final SWTGraphics2D g2 = (SWTGraphics2D) paintContext.getGraphics(); - protected void disposeImage() { - if (image != null) { - image.dispose(); - } - } - - protected void paint(final PPaintContext paintContext) { - if (getImage() != null) { - final Rectangle r = image.getBounds(); - final double iw = r.width; - final double ih = r.height; - final PBounds b = getBoundsReference(); - final SWTGraphics2D g2 = (SWTGraphics2D) paintContext.getGraphics(); - - if (b.x != 0 || b.y != 0 || b.width != iw || b.height != ih) { - g2.translate(b.x, b.y); - g2.scale(b.width / iw, b.height / ih); - g2.drawImage(image, 0, 0); - g2.scale(iw / b.width, ih / b.height); - g2.translate(-b.x, -b.y); - } - else { - g2.drawImage(image, 0, 0); - } - } - } + if (b.x == 0 && b.y == 0 && b.width == r.width + && b.height == r.height) { + g2.drawImage(image, 0, 0); + } else { + g2.translate(b.x, b.y); + g2.scale(b.width / r.width, b.height / r.height); + g2.drawImage(image, 0, 0); + g2.scale(r.width / b.width, r.height / b.height); + g2.translate(-b.x, -b.y); + } + } + } } diff --git a/swt/src/test/java/edu/umd/cs/piccolox/swt/PSWTImageTest.java b/swt/src/test/java/edu/umd/cs/piccolox/swt/PSWTImageTest.java new file mode 100644 index 0000000..25d362a --- /dev/null +++ b/swt/src/test/java/edu/umd/cs/piccolox/swt/PSWTImageTest.java @@ -0,0 +1,58 @@ +package edu.umd.cs.piccolox.swt; + +import java.io.File; + +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Display; + +public class PSWTImageTest extends SWTTest { + File imageFile; + PSWTCanvas canvas; + PSWTImage imageNode; + Image image; + + public void setUp() throws Exception { + if (hasHead()) { + final Display display = Display.getDefault(); + canvas = buildSimpleCanvas(display); + imageNode = new PSWTImage(canvas); + image = new Image(display, new Rectangle(0, 0, 100, 100)); + } + } + + public void testImageShouldDefaultToNull() { + if (hasHead()) { + assertNull(imageNode.getImage()); + } + } + + public void testPaintShouldDoNothingWhenImageIsNull() { + if (hasHead()) { + // if it tries to use the graphics context, it would throw a NPE + imageNode.paint(null); + } + } + + public void testImageInConstructorPersists() { + if (hasHead()) { + imageNode = new PSWTImage(canvas, image); + assertSame(image, imageNode.getImage()); + } + } + + public void testDisposingCanvasDisposesImage() { + if (hasHead()) { + final boolean[] called = new boolean[1]; + called[0] = false; + imageNode = new PSWTImage(canvas, image) { + protected void disposeImage() { + called[0] = true; + super.disposeImage(); + } + }; + canvas.dispose(); + assertTrue(called[0]); + } + } +} diff --git a/swt/src/test/java/edu/umd/cs/piccolox/swt/SWTTest.java b/swt/src/test/java/edu/umd/cs/piccolox/swt/SWTTest.java index a04b19f..18eb23f 100644 --- a/swt/src/test/java/edu/umd/cs/piccolox/swt/SWTTest.java +++ b/swt/src/test/java/edu/umd/cs/piccolox/swt/SWTTest.java @@ -2,14 +2,24 @@ import java.awt.GraphicsEnvironment; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; + import junit.framework.TestCase; -public abstract class SWTTest extends TestCase { +public abstract class SWTTest extends TestCase { public final boolean isHeadless() { return GraphicsEnvironment.isHeadless(); } - public final boolean hasHead() { + protected final boolean hasHead() { return !isHeadless(); } + + protected PSWTCanvas buildSimpleCanvas(Display display) { + final Shell shell = new Shell(display); + shell.setLayout(new FillLayout()); + return new PSWTCanvas(shell, 0); + } }