/* ========================
* JSynoptic : a free Synoptic editor
* ========================
*
* Project Info: http://jsynoptic.sourceforge.net/index.html
*
* This program 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 program 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
* program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* (C) Copyright 2003, by :
* Corporate:
* Astrium SAS
* EADS CRC
* Individual:
* Nicolas Brodu
*
* $Id: ImageShape.java,v 1.22 2008/09/05 12:23:22 ogor Exp $
*
* Changes
* -------
* 24-Nov-2003 : Creation date (NB);
*
*/
package jsynoptic.builtin;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.ResourceBundle;
import javax.imageio.ImageIO;
import jsynoptic.builtin.ui.ImagePropertiesPanel;
import simtools.data.DataException;
import simtools.data.DataSource;
import simtools.data.DataSourcePool;
import simtools.data.UnsupportedOperation;
import simtools.shapes.AbstractShape;
import simtools.ui.BasicMessageWriter;
import simtools.ui.ImageMapper;
import simtools.ui.JPropertiesPanel;
import simtools.ui.ResourceFinder;
import simtools.util.CurrentPathProvider;
import simtools.util.FileSerializer;
import simtools.util.ImageSerializer;
/**
* An image shape will draw an image (how suprising!) It can also draw a dynamic
* colored frame, and change the image displayed dynamically according to data
* values.
*
*/
public class ImageShape extends Abstract1DShape {
static final long serialVersionUID = 8701487979765549739L;
public static ResourceBundle resources = ResourceFinder.get(ImageShape.class);
public static BasicMessageWriter messageWriter = ResourceFinder.getMessages(ImageShape.class);
protected transient BufferedImage image, dynamicImage = null;
protected ImageMapper mapper;
protected transient DataSource source;
protected transient long index;
protected transient boolean dirtyImage = false;
// This field is nice to have for the user, when changing the image => keep
// the location
protected transient File currentFile = null;
/**
* The relative path to the file is serialized
*/
protected String currentFileRelativePath;
/**
* If the image should be scaled to fit the shape size (autoFit true), else
* the shape will be resized
*/
protected boolean autoFit;
/**
* If the image should be scaled to fit the shape size (autoFit true), else
* the shape will be resized
*/
public boolean isAutoFit() {
return autoFit;
}
/**
* If the image should be scaled to fit the shape size (autoFit true), else
* the shape will be resized
*/
public void setAutoFit(boolean autoFit) {
this.autoFit = autoFit;
}
public ImageShape(File f, int ox, int oy) {
super(ox, oy, 100, 100);
try {
image = ImageIO.read(f);
_w = image.getWidth();
_h = image.getHeight();
} catch (IOException e) {
image = null;
}
autoFit = false;
}
/**
* @param ox
* @param oy
* @param width
* @param height
*/
public ImageShape(int ox, int oy, int width, int height) {
super(ox, oy, width, height);
image = null;
}
/*
* (non-Javadoc)
*
* @see jsynoptic.builtin.Abstract1DShape#getDelegateShape()
*/
protected Shape getDelegateShape() {
return new Rectangle(_ox, _oy - _h, _w - 1, _h - 1);
}
/*
* (non-Javadoc)
*
* @see simtools.shapes.AbstractShape#cloneShape()
*/
protected AbstractShape cloneShape() {
// try {
ImageShape clone = (ImageShape) super.cloneShape();
if (clone.source != null) {
clone.source.addListener(clone);
clone.source.addEndNotificationListener(clone);
}
return clone;
// } catch (CloneNotSupportedException cnse) {}
// return null;
}
/*
* (non-Javadoc)
*
* @see jsynoptic.builtin.Abstract1DShape#drawHook(java.awt.Graphics2D,
* boolean)
*/
protected void drawHook(Graphics2D g, boolean shapeDrawn) {
// Draw image before frame
if (shapeDrawn) {
return;
}
BufferedImage img = (dynamicImage != null) ? dynamicImage : image;
if (img != null) {
g.drawImage(img, _ox, _oy - _h, _w, _h, null);
}
}
/* (non-Javadoc)
* @see jsynoptic.builtin.Abstract2DShape#getPanel(java.util.List)
*/
public JPropertiesPanel getPanel(List properties) {
if (properties == null){
return null;
}
if (properties.containsAll(Arrays.asList(new ImageShapePropertiesNames().getPropertyNames()))){
return new ImagePropertiesPanel(Builtin.resources.getString("Image"));
} else {
return super.getPanel(properties);
}
}
/* (non-Javadoc)
* @see simtools.shapes.AbstractShape#getShapeName()
*/
public String getShapeName(){
return Builtin.resources.getString("Image");
}
/**
* Get current dynamic image and repaint shape when necessay.
*
* - If dynamic image has changed and is not null -> display this dynamic image
* - If dynamic image is null but previous dynamic image was not null -> display default image
*
* - Otherwise no repaint is performed
*/
protected void resheshImage() {
//Repaint only when necessay
boolean repaint = false;
BufferedImage img = getDynamicImage();
if (img == null) {
repaint = (dynamicImage != null);
} else {
repaint = !img.equals(dynamicImage);
}
dynamicImage = img;
// Repaint our area if the color changed, do a redraw only when
// necessary
if (repaint) {
int w = _w, h = _h;
if (!autoFit) {
if (dynamicImage != null) {
_w = dynamicImage.getWidth();
_h = dynamicImage.getHeight();
} else if (image != null) {
_w = image.getWidth();
_h = image.getHeight();
}
w = Math.max(w, _w);
h = Math.max(h, _h);
}
dirtyRectangle = new Rectangle(_ox, _oy - h, w, h);
dirty = true;
}
}
/**
* @return
* @throws DataException
*/
protected Object getSourceValue() throws DataException {
if (source != null) {
return source.getValue(index);
}
return null;
}
/**
* @return a BufferedImage that matches with mapped data source value
* or null if not match found
*/
protected BufferedImage getDynamicImage() {
BufferedImage img = null;
if (mapper != null) {
try {
ImageMapper.ImageFile imf = (ImageMapper.ImageFile) mapper.getMapping(getSourceValue());
if (imf != null) {
if ((imf.image == null) && (imf.file != null)) {
try {
imf.image = ImageIO.read(imf.file);
} catch (IOException e1) {
imf.image = null;
}
}
img = imf.image;
}
} catch (DataException e) {
}
}
return img;
}
/*
* (non-Javadoc)
*
* @see simtools.data.EndNotificationListener#notificationEnd(java.lang.Object)
*/
public void notificationEnd(Object referer) {
// Get dynamic image value
if (dirtyImage) {
dirtyImage = false;
resheshImage();
}
super.notificationEnd(referer);
}
/*
* (non-Javadoc)
*
* @see simtools.data.DataSourceListener#DataSourceIndexRangeChanged(simtools.data.DataSource,
* long, long)
*/
public void DataSourceIndexRangeChanged(DataSource ds, long startIndex, long lastIndex) {
if (ds.equals(this.source)) {
index = lastIndex;
dirtyImage = true;
}
super.DataSourceIndexRangeChanged(ds, startIndex, lastIndex);
}
/*
* (non-Javadoc)
*
* @see simtools.data.DataSourceListener#DataSourceValueChanged(simtools.data.DataSource,
* long, long)
*/
public void DataSourceValueChanged(DataSource ds, long minIndex, long maxIndex) {
if (ds.equals(this.source)) {
// We care only about our index value change
if ((index >= minIndex) && (index <= maxIndex)) {
dirtyImage = true;
}
}
super.DataSourceValueChanged(ds, minIndex, maxIndex);
}
/*
* (non-Javadoc)
*
* @see simtools.data.DataSourceListener#DataSourceReplaced(simtools.data.DataSource,
* simtools.data.DataSource)
*/
public void DataSourceReplaced(DataSource oldData, DataSource newData) {
if (oldData == source) {
source = newData;
if (source != null) {
source.addListener(this);
source.addEndNotificationListener(this);
try {
index = source.getLastIndex();
} catch (UnsupportedOperation e) {
index = 0;
}
}
oldData.removeListener(this);
oldData.removeEndNotificationListener(this);
resheshImage(); // Refresh image value now
}
super.DataSourceReplaced(oldData, newData);
}
/* (non-Javadoc)
* @see simtools.shapes.AbstractShape#subscribeToDataNotifications()
*/
public void processShapeRestoring(){
if (source!=null) {
source.addListener(this);
source.addEndNotificationListener(this);
try {
index = source.getLastIndex();
} catch (UnsupportedOperation uo1) {
index = 0;
}
}
super.processShapeRestoring();
}
/* (non-Javadoc)
* @see simtools.shapes.AbstractShape#unsubscribeToDataNotifications()
*/
public void processShapeRemoving(){
if (source != null) {
source.removeListener(this);
source.removeEndNotificationListener(this);
}
super.processShapeRemoving();
}
// Take care of serialisation. Special handling for datasources
private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {
// Set image file relative path from file
if (currentFile != null) {
currentFileRelativePath = FileSerializer.writeIntoString(currentFile,
CurrentPathProvider.currentPathProvider.getCurrentPath());
}
// Serialize other data
out.defaultWriteObject();
DataSourcePool.global.writeDataSource(out, source);
ImageSerializer.write(out, image);
}
private void readObject(java.io.ObjectInputStream in) throws java.lang.ClassNotFoundException, java.io.IOException {
in.defaultReadObject();
source = DataSourcePool.global.readDataSource(in);
image = ImageSerializer.read(in);
// Get file form serialized reltive path
if (currentFileRelativePath != null) {
currentFile = FileSerializer.readFromString(currentFileRelativePath,
CurrentPathProvider.currentPathProvider.getCurrentPath());
}
if (source != null) {
try {
source.addListener(this);
source.addEndNotificationListener(this);
index = source.getLastIndex();
} catch (UnsupportedOperation uo1) {
index = 0;
}
}
if (mapper != null) {
mapper = ImageMapper.updateImageMapper(mapper);
}
resheshImage();
}
/*
* (non-Javadoc)
*
* @see simtools.shapes.AbstractShape#getProperty(java.lang.String)
*/
public Object getPropertyValue(String name) {
Object res = super.getPropertyValue(name);
if (name.equalsIgnoreCase("IMAGE_FIT_TO_OBJECT")) {
res = new Boolean(autoFit);
} else if (name.equalsIgnoreCase("IMAGE_FILE")) {
res = currentFile;
} else if (name.equalsIgnoreCase("IMAGE_MAPPER")) {
res = mapper;
} else if (name.equalsIgnoreCase("IMAGE_MAPPER_SOURCE")) {
res = source;
}
return res;
}
/*
* (non-Javadoc)
*
* @see simtools.shapes.AbstractShape#setProperty(java.lang.String,
* java.lang.Object)
*/
public void setPropertyValue(String name, Object value) {
super.setPropertyValue(name, value);
if (name.equalsIgnoreCase("IMAGE_FIT_TO_OBJECT")) {
if (value instanceof Boolean) {
autoFit = ((Boolean) value).booleanValue();
}
} else if (name.equalsIgnoreCase("IMAGE_FILE")) {
if (value instanceof File) {
currentFile = (File) value;
try {
image = ImageIO.read(currentFile);
} catch (IOException e1) {
image = null;
}
} else {
currentFile = null;
image = null;
}
dirty = true;
} else if (name.equalsIgnoreCase("IMAGE_MAPPER")) {
if (value instanceof ImageMapper) {
mapper = (ImageMapper) value;
} else {
mapper = null;
}
} else if (name.equalsIgnoreCase("IMAGE_MAPPER_SOURCE")) {
if (source != null) {
source.removeListener(this);
source.removeEndNotificationListener(this);
}
if (value instanceof DataSource) {
source = (DataSource) value;
try {
index = source.getLastIndex();
} catch (UnsupportedOperation e) {
index = 0;
}
source.addListener(ImageShape.this);
source.addEndNotificationListener(ImageShape.this);
} else {
source = null;
}
dynamicImage = null; // wait for next update if any
resheshImage();
}
}
public String[] getPropertyNames() {
if (_propertyNames == null) {
_propertyNames = new ImageShapePropertiesNames().getPropertyNames();
}
return _propertyNames;
}
public static class ImageShapePropertiesNames extends Abstract1DShapePropertiesNames {
private static transient String[] props = new String[] {
"IMAGE_FIT_TO_OBJECT",
"IMAGE_FILE",
"IMAGE_MAPPER",
"IMAGE_MAPPER_SOURCE" };
public ImageShapePropertiesNames() {
super();
for (int i = 0; i < props.length; i++) {
propertyNames.add(props[i]);
}
}
}
/*
* (non-Javadoc)
*
* @see simtools.shapes.AbstractShape#wipeOff()
*/
public void wipeOff() {
if (mapper != null) {
mapper.wipeOff();
}
super.wipeOff();
}
}