/*
* File : MediaBagElement.java
* Created : 19-dec-2000 15:36
* By : fbusquets
*
* JClic - Authoring and playing system for educational activities
*
* Copyright (C) 2000 - 2005 Francesc Busquets & Departament
* d'Educacio de la Generalitat de Catalunya
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 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 General Public License for more details (see the LICENSE file).
*/
package edu.xtec.jclic.bags;
import edu.xtec.jclic.edit.Editable;
import edu.xtec.jclic.edit.Editor;
import edu.xtec.jclic.fileSystem.FileSystem;
import edu.xtec.jclic.misc.Utils;
import edu.xtec.util.Domable;
import edu.xtec.util.JDomUtility;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import javax.swing.ImageIcon;
import net.sf.image4j.codec.bmp.BMPDecoder;
import net.sf.image4j.codec.ico.ICODecoder;
/**
* <CODE>MediaBagElements</CODE> are the members of {@link edu.xtec.jclic.bags.MediaBag}
* objects. Media elements have a name, a reference to a file (the <CODE>fileName</CODE>)
* and, when initialized, a <CODE>data</CODE> field containing the raw content of
* the media. They have also a flag indicating if the data must be saved into the
* {@link edu.xtec.jclic.project.JClicProject} file or must be mantained as a single
* reference to a external file.
* @author Francesc Busquets (fbusquets@xtec.cat)
* @version 13.08.28
*/
public class MediaBagElement extends Object implements Editable, Domable, Comparable {
private String name;
private String fileName;
private int usageCount;
private Object data;
public boolean projectFlag;
public boolean saveFlag;
public boolean animated;
private boolean hasThumb;
private boolean isGif;
// 10-Aug-2015
// Added to allow renaming of media files
private String metadata;
/** Creates new MediaBagElement */
public MediaBagElement(String fileName) {
this(fileName, null);
}
public MediaBagElement(String fileName, Object data) {
this(fileName, data, fileName);
}
public MediaBagElement(String fileName, Object data, String name) {
setName(name);
setFileName(fileName);
setData(data);
usageCount = 0;
animated = false;
saveFlag = true;
}
public static final String ELEMENT_NAME = "media";
public static final String FILE = "file", NAME = "name", SAVE = "save", USAGE = "usage", ANIMATED = "animated";
public org.jdom.Element getJDomElement() {
org.jdom.Element e = new org.jdom.Element(ELEMENT_NAME);
e.setAttribute(NAME, name);
e.setAttribute(FILE, fileName);
if (!saveFlag)
e.setAttribute(SAVE, JDomUtility.BOOL_STR[JDomUtility.FALSE]);
if (usageCount > 0)
e.setAttribute(USAGE, Integer.toString(usageCount));
if (isGif)
e.setAttribute(ANIMATED, JDomUtility.BOOL_STR[animated ? JDomUtility.TRUE : JDomUtility.FALSE]);
return e;
}
protected static MediaBagElement getMediaBagElement(org.jdom.Element e) throws Exception {
MediaBagElement mb = new MediaBagElement("NONAME", null);
mb.setProperties(e, null);
return mb;
}
public void setProperties(org.jdom.Element e, Object aux) throws Exception {
JDomUtility.checkName(e, ELEMENT_NAME);
setName(JDomUtility.getStringAttr(e, NAME, name, false));
setFileName(JDomUtility.getStringAttr(e, FILE, fileName, false));
saveFlag = JDomUtility.getBoolAttr(e, SAVE, true);
usageCount = JDomUtility.getIntAttr(e, USAGE, usageCount);
animated = JDomUtility.getBoolAttr(e, ANIMATED, false);
}
public Editor getEditor(Editor parent) {
return Editor.createEditor(getClass().getName() + "Editor", this, parent);
}
public boolean isEmpty() {
return data == null;
}
public void setFileName(String sName) {
fileName = FileSystem.stdFn(sName);
data = null;
animated = false;
isGif = fileName.toLowerCase().endsWith(".gif");
}
public String getFileName() {
return fileName;
}
public void setMetaData(String meta) {
metadata = meta;
}
public String getMetaData() {
return metadata;
}
public boolean isImage() {
return Utils.getFileType(fileName) == Utils.TYPE_IMAGE;
}
public void setData(Object sData) {
data = sData;
// CHANGED: 28/Apr/2016 - Don't clear animated flag!
// animated=false;
if (data != null && data instanceof Image)
Toolkit.getDefaultToolkit().prepareImage((Image) data, -1, -1, null);
}
public void clearData() {
if (data != null && !(data instanceof java.awt.Font)) {
if (data instanceof Image)
((Image) data).flush();
setData(null);
}
}
public Object getData() {
return data;
}
public boolean isInternal() {
return (data != null);
}
public void incUsageCount() {
usageCount++;
}
public void decUsageCount() {
usageCount--;
}
public boolean isUsed() {
return usageCount <= 0;
}
@Override
protected void finalize() throws Throwable {
Image img = getImage();
if (img != null)
img.flush();
data = null;
super.finalize();
}
public boolean prepareImage(FileSystem fs) throws Exception {
boolean result = false;
if (isImage()) {
if (data == null || !(data instanceof Image)) {
String fn = fileName.toLowerCase();
if (fn.endsWith(".bmp")) {
// Old edu.xtec.jclic.misc.Bmp replaced by image4j
//Bmp bmp=new Bmp(fs.getInputStream(fileName));
//setData(bmp.getImage());
BufferedImage img = BMPDecoder.read(fs.getInputStream(fileName));
setData(Toolkit.getDefaultToolkit().createImage(img.getSource()));
} else if (fn.endsWith(".ico")) {
java.util.List list = ICODecoder.read(fs.getInputStream(fileName));
int maxs = 0;
BufferedImage img = null;
int listSize = list.size();
for (int i = 0; i < listSize; i++) {
BufferedImage imgtmp = (BufferedImage) list.get(i);
int s = imgtmp.getWidth() * imgtmp.getHeight();
if (s >= maxs) {
img = imgtmp;
maxs = s;
}
}
if (img != null)
setData(Toolkit.getDefaultToolkit().createImage(img.getSource()));
} else
setData(fs.getImageFile(fileName));
}
result = true;
}
return result;
}
private static int imgReadyFlag = (ImageObserver.WIDTH | ImageObserver.HEIGHT);
public Image getImage() throws Exception {
int imgStatus = 0;
if (data == null || !(data instanceof Image))
return null;
if (!animated)
while (true) {
imgStatus = Toolkit.getDefaultToolkit().checkImage((Image) data, -1, -1, null);
if ((imgStatus & (ImageObserver.ERROR | ImageObserver.ABORT)) != 0) {
System.err.println(
"Error loading " + getName() + " - Toolkit.checkImage returned status: " + imgStatus);
data = null;
break;
} else if ((imgStatus & imgReadyFlag) == imgReadyFlag)
break;
Thread.sleep(50);
}
if (data != null && (imgStatus & ImageObserver.FRAMEBITS) != 0)
animated = true;
return (Image) data;
}
public Image prepareAndGetImage(FileSystem fs) throws Exception {
Image img = getImage();
if (img == null && data == null) {
if (prepareImage(fs))
img = getImage();
}
return img;
}
public ImageIcon getThumbNail(int maxWidth, int maxHeight, FileSystem fs) {
ImageIcon result = null;
try {
Image img = prepareAndGetImage(fs);
if (img == null) {
img = Utils.getFileIcon(fileName).getImage();
}
if (img != null && maxWidth > 0 && maxHeight > 0) {
int w = img.getWidth(null);
int h = img.getHeight(null);
if (w > 0 && h > 0 && (w > maxWidth || h > maxHeight)) {
double f = Math.min((double) maxWidth / w, (double) maxHeight / h);
img = img.getScaledInstance((int) (f * w), (int) (f * h), Image.SCALE_SMOOTH);
}
result = new ImageIcon(img);
hasThumb = true;
}
} catch (Exception ex) {
System.err.println("Error reading image:\n" + ex);
}
return result;
}
public boolean isWaitingForImage() {
if (hasThumb == true || animated == true || data == null || !(data instanceof Image))
return false;
int state = Toolkit.getDefaultToolkit().checkImage((Image) data, -1, -1, null);
if ((state & ImageObserver.FRAMEBITS) != 0) {
animated = true;
}
boolean result = (state & (ImageObserver.ALLBITS | ImageObserver.FRAMEBITS)) == 0;
return result;
}
/** Getter for property name.
* @return Value of property name.
*
*/
public java.lang.String getName() {
return name;
}
/** Setter for property name.
* @param name New value of property name.
*
*/
public void setName(String name) {
this.name = FileSystem.stdFn(name);
}
@Override
public String toString() {
return name;
}
public int compareTo(Object obj) {
int result = -1;
if (getName() != null && obj instanceof MediaBagElement) {
result = getName().compareTo(((MediaBagElement) obj).getName());
}
return result;
}
}