package net.sf.jiga.xtended.ui;/*
* Display.java
*
* Created on 24 novembre 2006, 05:37
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JComponent;
import net.sf.jiga.xtended.kernel.JXAenvUtils;
import net.sf.jiga.xtended.kernel.Monitor;
import net.sf.jiga.xtended.kernel.Resource;
import net.sf.jiga.xtended.kernel.Threaded;
/**
* This class allows to display an Image in a component that can be added to any Container.
* Component will be scaled to Image size to fit it.
* It is synchronized on the component with the MediaTracker.
*@see #mt
* @see Image
*@see MediaTracker
* @author www.b23prodtm.info
*/
public class Display extends JComponent implements Resource, Threaded, DisplayInterface {
/** the MediaTracker to manage full loading of the image data */
private MediaTracker mt;
/** the image to display */
private Image display;
/** phantom ref to image */
private PhantomReference phantomImage;
/** Transform instance to scale the image */
private AffineTransform tx;
/** background color
* @default Color.LIGHT_GRAY */
private Color background = Color.LIGHT_GRAY;
/** the original size */
private Dimension originalBox;
/** the BufferedImage instance */
private BufferedImage bgImg;
/** the ReferenceQueue instance for Garbage collecting */
private ReferenceQueue<? extends Image> refQueue = new ReferenceQueue<Image>();
/***/
private String text = null;
/***/
private int align = UIMessage.UI_CENTER;
private Point pad;
/** Text positioning
* x. left-right padding
y. top-bottom padding*/
public void setPadding(Point pad) {
this.pad = pad;
}
/**
@see UIMessage#UI_CENTER
@see UIMessage#UI_BOTTOM
@see UIMessage#UI__BOTTOM_LEFT
@see UIMessage#UI_BOTTOM_RIGHT
@see UIMessage#UI_TOP_LEFT
@see UIMessage#UI_TOP_RIGHT
*/
public void setAlign(int align) {
this.align = align;
}
/** adds text to the Display */
public void setText(String text) {
this.text = text;
}
/** modifies Text Color*/
@Override
public void setForeground(Color fg) {
super.setForeground(fg);
}
/** modifies Text Font */
@Override
public void setFont(Font font) {
super.setFont(font);
}
public String getText() {
return text;
}
/** creates a new instance
@param filename the file name to the image to display
@param tx the AffineTransform instance to add transform effect
@see #Display(Image, AffineTransform)*/
public static DisplayInterface _Display(String filename, AffineTransform tx) throws IOException {
return new Display(filename, tx);
}
private Display(String filename, AffineTransform tx) throws IOException {
this(ImageIO.read(new File(filename)), tx);
}
/** creates a new instance
@param filename the file name to the image to display
@param tx the AffineTransform instance to add transform effect
@see #Display(Image, AffineTransform)*/
public static DisplayInterface _Display(URL filename, AffineTransform tx) throws IOException, URISyntaxException {
return new Display(filename, tx);
}
private Display(URL filename, AffineTransform tx) throws IOException, URISyntaxException {
this(ImageIO.read(filename), tx);
}
/** creates a new instance
@param filename the file name to the image to display
@param tx the AffineTransform instance to add transform effect
* @param size the size to set up as preferred size
@see #Display(Image, AffineTransform, Dimension)*/
public static DisplayInterface _Display(String filename, AffineTransform tx, Dimension size) throws IOException {
return new Display(filename, tx, size);
}
private Display(String filename, AffineTransform tx, Dimension size) throws IOException {
this(ImageIO.read(new File(filename)), tx, size);
}
/** creates a new instance
@param filename the file name to the image to display
@param tx the AffineTransform instance to add transform effect
* @param size the size to set up as preferred size
@see #Display(Image, AffineTransform, Dimension)*/
public static DisplayInterface _Display(URL filename, AffineTransform tx, Dimension size) throws IOException, URISyntaxException {
return new Display(filename, tx, size);
}
private Display(URL filename, AffineTransform tx, Dimension size) throws IOException, URISyntaxException {
this(ImageIO.read(filename), tx, size);
}
/** the validity switch */
private transient boolean valid = false;
/** creates a new instance
* @param pdisplay the image to display
* @param ptx the transform to apply to the displayed image */
public static DisplayInterface _Display(Image pdisplay, AffineTransform ptx) {
return new Display(pdisplay, ptx);
}
private Display(Image pdisplay, AffineTransform ptx) {
super();
setGroupMonitor(new Monitor());
display = pdisplay;
tx = ptx;
loadResource();
setPreferredSize(originalBox);
setSize(getPreferredSize());
}
/** creates a new instance
* @param pdisplay the image to display
* @param ptx the transform to apply to the displayed image
@param psize the size to set up the preferred size */
public static DisplayInterface _Display(Image pdisplay, AffineTransform ptx, Dimension psize) {
return new Display(pdisplay, ptx, psize);
}
private Display(Image pdisplay, AffineTransform ptx, Dimension psize) {
super();
setPreferredSize(psize);
setSize(getPreferredSize());
setGroupMonitor(new Monitor());
display = pdisplay;
tx = ptx;
loadResource();
}
/** finalization */
public void finalize() {
clearResource();
try {
super.finalize();
} catch (Throwable ex) {
ex.printStackTrace();
}
}
/** sets up the background color
* @param color the background color to use*/
public void setBGColor(Color color) {
background = color;
}
/** returns the picture being displayed in this component
* @return the displayed picture*/
public Image getPicture() {
return display;
}
/** sets up the AffineTransform instance to use for the transform effect
@param tx the AffineTransform instance to use for the transform effect */
public void setTX(AffineTransform tx) {
this.tx = tx;
}
/** returns the AffineTransform instance used for the transform effect
@return the AffineTransform instance used for the transform effect
@see #setTX(AffineTransform)*/
public AffineTransform getTX() {
return tx;
}
boolean opaque = super.isOpaque();
@Override
public void setOpaque(boolean isOpaque) {
super.setOpaque(isOpaque);
opaque = isOpaque;
}
/** returns always true
@return true*/
public boolean isOpaque() {
return opaque;
}
/** the current applied transform effect */
private AffineTransform currentTx = new AffineTransform();
/***/
private Dimension currentImageSize = new Dimension();
/** paint the JComponent instance
* @param g1 the Graphics instance*/
protected void paintComponent(Graphics g1) {
if (!valid) {
return;
}
final Monitor monitor = imageSynch;
Rectangle clip = g1.getClipBounds();
try {
synchronized (monitor) {
Dimension currentSize = new Dimension(getWidth(), getHeight());
Graphics2D g = (Graphics2D) g1;
g.clipRect(0, 0, currentSize.width, currentSize.height);
g.setBackground(background);
Composite cps = g.getComposite();
g.setColor(g.getBackground());
if (isOpaque()) {
g.fillRect(0, 0, currentSize.width, currentSize.height);
}
g.setColor(Color.BLACK);
AffineTransform bgResizeTx = AffineTransform.getScaleInstance((double) ((float) currentSize.width) / ((float) bgImg.getWidth(this)), (double) ((float) currentSize.height) / ((float) bgImg.getHeight(this)));
AffineTransform dispResizeTx = AffineTransform.getScaleInstance((double) ((float) currentSize.width) / ((float) display.getWidth(this)), (double) ((float) currentSize.height) / ((float) display.getHeight(this)));
if (!currentImageSize.equals(currentSize)) {
mt.addImage(bgImg, hashCode(), currentSize.width, currentSize.height);
}
if (!tx.equals(currentTx)) {
Rectangle box = this.tx.createTransformedShape(new Rectangle(0, 0, display.getWidth(this), display.getHeight(this))).getBounds();
if (!new Dimension(display.getWidth(this), display.getHeight(this)).equals(box.getSize())) {
mt.addImage(display, hashCode(), box.width, box.height);
}
mt.waitForAll();
cps = g.getComposite();
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.33f));
if (opaque) {
g.drawImage(bgImg, bgResizeTx, this);
}
g.setComposite(cps);
g.drawImage(display, tx, this);
currentTx = tx;
} else {
if (!currentImageSize.equals(currentSize)) {
mt.addImage(display, hashCode(), currentSize.width, currentSize.height);
}
mt.waitForAll();
cps = g.getComposite();
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.33f));
if (opaque) {
g.drawImage(bgImg, bgResizeTx, this);
}
g.setComposite(cps);
g.drawImage(display, dispResizeTx, this);
currentImageSize = currentSize;
}
mt.removeImage(bgImg, hashCode());
mt.removeImage(display, hashCode());
monitor.notify();
}
} catch (InterruptedException ex) {
if (JXAenvUtils._debugSys) {
ex.printStackTrace();
}
} finally {
if (text instanceof String) {
g1.setClip(clip);
clip.grow(-pad.x, -pad.y);
FontMetrics fm = g1.getFontMetrics();
Point loc = new Point(clip.getLocation());
/** place the popup */
// on the right
if ((align & UIMessage._RIGHT_) != 0) {
loc.x += clip.width - fm.stringWidth(text);
} else if ((align & UIMessage._LEFT_) == 0) {// center
loc.x += (int) clip.getCenterX() - Math.round(fm.stringWidth(text) / 2f);
} else {
} //left
// on bottom
if ((align & UIMessage._BOTTOM_) != 0) {
loc.y += clip.height - fm.getHeight();
} else if ((align & UIMessage._TOP_) == 0) { // center
loc.y += (int) clip.getCenterY() - Math.round(fm.getHeight() / 2f);
} else {
}//top
g1.setColor(getForeground());
g1.setFont(getFont());
g1.drawString(text, loc.x, loc.y);
}
g1.setClip(clip);
}
}
long hash = System.nanoTime();
public boolean equals(Object o) {
return o == null ? false : hashCode() == o.hashCode();
}
public int hashCode() {
return (int) hash;
}
public boolean isMultiThreadingEnabled() {
return JXAenvUtils._multiThreading;
}
public void setMultiThreadingEnabled(boolean b) {
JXAenvUtils._multiThreading = b;
}
/** not implemented
@see #clearResource()*/
public Object loadResource() {
final Monitor monitor = imageSynch;
try {
synchronized (monitor) {
if (display == null) {
return null;
}
phantomImage = new PhantomReference(display, refQueue);
String icon = "images/duke.gif";
bgImg = ImageIO.read(getClass().getResourceAsStream(icon));
mt = new MediaTracker(this);
mt.addImage(bgImg, hashCode());
mt.addImage(display, hashCode());
mt.waitForAll();
mt.removeImage(bgImg, hashCode());
mt.removeImage(display, hashCode());
if (tx != null) {
Display.this.tx = tx;
} else {
Display.this.tx = AffineTransform.getScaleInstance(1.0, 1.0);
}
originalBox = new Dimension(display.getWidth(this), display.getHeight(this));
valid = true;
monitor.notify();
}
} catch (Exception ex) {
if (JXAenvUtils._debugSys) {
ex.printStackTrace();
}
} finally {
return display;
}
}
/** clears the Resource
@see ReferenceQueue#poll()
@return null*/
public Object clearResource() {
Reference ref;
while ((ref = refQueue.poll()) instanceof Reference) {
ref.clear();
}
return null;
}
/** returns always true
@return true */
public boolean isResourceLoaded() {
return true;
}
/** the image synch */
private transient Monitor imageSynch;
public JComponent getJComponentDisplay() {
return this;
}
public Monitor[] getGroupMonitor() {
return new Monitor[]{imageSynch};
}
public void setGroupMonitor(Monitor... tg) {
imageSynch = tg[0];
}
}