/* ========================
* 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 2001-2005, by :
* Corporate:
* EADS Astrium SAS
* EADS CRC
* Individual:
* Claude Cazenave
*
* $Id: SVGFileHolder.java,v 1.8 2007/06/29 16:13:00 ogor Exp $
*
* Changes
* -------
* 20 d�c. 2005 : Initial public release (CC);
*
*/
package simtools.images.svg;
import java.io.File;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.Iterator;
import org.apache.batik.transcoder.TranscoderException;
import org.apache.batik.transcoder.TranscoderInput;
import simtools.images.svg.SVGImageFactory.FactoryListener;
/**
* The holder of one SVG document in charge of computing the images
* for each requested sizes
*
* @author cazenave_c
*/
public class SVGFileHolder {
/**
* The SVG file
*/
protected final File file;
/**
* The SVG url
*/
protected final String url;
/**
* The batik transoder SVG input
*/
protected final TranscoderInput tinput;
/**
* All the generated images with different sizes
* The key contains the size specification
* @see #getKey(int, int)
* The value is a <code>ImageHolder</code> which contains
* the image and all the related listeners
*/
protected HashMap imageElements;
/**
* The <code>SVGImageFactory</code> in charge of this holder
*/
protected final SVGImageFactory factory;
/**
* Width and height for the original document. They are set to -1 until the size is known
*/
protected int width,height;
/**
* Construct a new SVG holder
* @param factory
* @param f
*/
public SVGFileHolder(SVGImageFactory factory, File f){
width=-1;
height=-1;
this.factory=factory;
file=f;
if(file.canRead()){
String u=null;
try {
u = file.toURL().toString();
} catch (MalformedURLException e1) {
}
finally{
url=u;
if(u!=null){
tinput = new TranscoderInput(url);
}
else{
tinput=null;
}
}
}
else{
url=null;
tinput=null;
}
imageElements=new HashMap();
}
/**
* Check if the holder is empty i.e. there is no more
* user of this SVG file
* @return true if empty
*/
public boolean isEmpty(){
return imageElements.size()==0;
}
/**
* Get the file managed by this hoder
* @return the file
*/
public File getFile() {
return file;
}
/**
* Release one of the user of this SVG file
* If there is no more user the related image is freed
* @param l the user listener
*/
public void relase(FactoryListener l) {
synchronized(imageElements){
Iterator it=imageElements.values().iterator();
while(it.hasNext()){
ImageHolder ih=(ImageHolder)it.next();
synchronized(ih.listeners){
ih.listeners.remove(l);
if(ih.listeners.isEmpty()){
ih.image=null; // free memory
it.remove();
}
}
}
}
}
/**
* Save the image for one of the user of this SVG file
* @param l the user listener
* @throws IOException
*/
public void write(ObjectOutputStream out, FactoryListener l) throws IOException {
synchronized(imageElements){
Iterator it=imageElements.values().iterator();
while(it.hasNext()){
ImageHolder ih=(ImageHolder)it.next();
if(ih.listeners.contains(l)){
out.writeObject(ih);
return;
}
}
}
out.writeObject(null);
}
/**e
* Read the image for one of the user of this SVG file
* @param l the user listener
* @throws IOException
* @throws ClassNotFoundException
*/
public void read(ObjectInputStream in, FactoryListener l) throws IOException, ClassNotFoundException {
ImageHolder ih=(ImageHolder) in.readObject();
if (ih!=null){
ih.setHolder(this);
if(ih.image!=null){
synchronized(imageElements){
Object key=getKey(ih.image.getWidth(),ih.image.getHeight());
imageElements.put(key, ih);
}
}
ih.listeners.add(l);
l.done(ih.image);
}
}
/**
* Generate a key for an image managed by this holder
* @param w the image width
* @param h the image height
* @return the key
*/
public Object getKey(int w, int h){
if(width==w && height==h){
return ""+(-1)+","+(-1);
}
else{
return ""+w+","+h;
}
}
/**
* Get an image of the specified size from the SVG file
* If the image is not yet available then return null
* @param w the image width
* @param h the image height
* @return the image holder
*/
public ImageHolder get(int w, int h) {
Object key = getKey(w, h);
synchronized (imageElements) {
ImageHolder pih = (ImageHolder) imageElements.get(key);
if (pih != null) {
return pih;
}
pih = (ImageHolder) imageElements.get(getKey(width, height));
if (pih != null) {
return pih;
}
Iterator it=imageElements.values().iterator();
if(it.hasNext()){
pih= (ImageHolder)it.next();
if (pih != null) {
return pih;
}
}
}
return null;
}
/**
* Generate an image of the specified size from the SVG file
* The listener gets back (the image or an error message)
* If the image is not yet available, it is generated in a thread
* if background is set to true
* @param w the image width
* @param h the image height
* @param l the listener
* @param background equals true to do the process in a new thread
*/
public void generate(final int w, final int h, FactoryListener l, boolean background) {
if (tinput!=null){
final Object key = getKey(w, h);
final ImageHolder fih = new ImageHolder(this);
synchronized (imageElements) {
ImageHolder pih = (ImageHolder) imageElements.get(key);
if ((pih != null) ){
pih.listeners.add(l);
l.done(pih.image); // may be null if not fully transcoded yet
return;
} else {
imageElements.put(key, fih);
}
}
fih.listeners.add(l);
final FactoryTranscoder ft = factory.createFactoryTranscoder(fih);
if (background) {
Thread t = new Thread() {
public void run() {
try {
ft.rasterize(tinput, w, h);
width=ft.getWidth();
height=ft.getHeight();
} catch (TranscoderException e1) {
String msg = e1.getMessage();
for (int i = 0; i < fih.listeners.size(); i++) {
((FactoryListener) fih.listeners.get(i))
.failed(msg);
}
}
}
};
t.start();
} else {
try {
ft.rasterize(tinput, w, h);
width=ft.getWidth();
height=ft.getHeight();
} catch (TranscoderException e1) {
String msg = e1.getMessage();
for (int i = 0; i < fih.listeners.size(); i++) {
((FactoryListener) fih.listeners.get(i)).failed(msg);
}
}
}
}
}
}