/*
* File : ActiveBagContent.java
* Created : 27-apr-2001 17:11
* 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.boxes;
import edu.xtec.jclic.Activity;
import edu.xtec.jclic.Constants;
import edu.xtec.jclic.PlayStation;
import edu.xtec.jclic.bags.MediaBag;
import edu.xtec.jclic.bags.MediaBagElement;
import edu.xtec.jclic.fileSystem.FileSystem;
import edu.xtec.jclic.shapers.Rectangular;
import edu.xtec.jclic.shapers.Shaper;
import edu.xtec.util.Domable;
import edu.xtec.util.JDomUtility;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
/**
* This class stores a collection of {@link edu.xtec.jclic.boxes.ActiveBoxContent}
* objects, currently in a {@link java.util.ArrayList}, and provides methods to
* manage it. The two main members of <CODE>ActiveBagContent</CODE> are the
* {@link edu.xtec.jclic.shapers.Shaper}, responsible of determining the position and shape of each
* {@link edu.xtec.jclic.boxes.ActiveBox} based on it, and the
* {@link edu.xtec.jclic.boxes.BoxBase}, that provides a common visual style.
* @author Francesc Busquets (fbusquets@xtec.cat)
* @version 13.09.09
*/
public class ActiveBagContent extends Object implements Domable{
public Image img;
public String imgName;
public int ncw, nch;
public double w, h;
public boolean border;
public BoxBase bb;
protected Shaper shaper;
protected ActiveBoxContent backgroundContent;
protected ArrayList<ActiveBoxContent> activeBoxContentArray = new ArrayList<ActiveBoxContent>(12);
public int defaultIdValue=-1;
/** Creates new ActiveBagContent */
private ActiveBagContent() {
}
public ActiveBagContent(int ncw, int nch){
this.ncw=Math.max(1, ncw);
this.nch=Math.max(1, nch);
w=Activity.DEFAULT_GRID_ELEMENT_SIZE;
h=Activity.DEFAULT_GRID_ELEMENT_SIZE;
}
public static ActiveBagContent initNew(int ncw, int nch, int firstChar){
return initNew(ncw, nch, firstChar, false, false, 50, 30);
};
public static ActiveBagContent initNew(int ncw, int nch, int firstChar,
boolean withIds, boolean withItems,
int w, int h){
ActiveBagContent result=new ActiveBagContent(ncw, nch);
result.w=w;
result.h=h;
result.setBoxBase(new BoxBase());
result.border=true;
char[] ch=null;
if(firstChar>0){
ch=new char[]{(char)firstChar};
}
for(int i=0; i<nch; i++){
for(int j=0; j<ncw; j++){
ActiveBoxContent ab=new ActiveBoxContent();
if(ch!=null){
ab.setTextContent("");
ch[0]++;
}
else{
//ab.setTextContent("-");
ab.setTextContent("");
}
if(withIds){
if(withItems){
ab.id=j;
ab.item=i;
}
else{
ab.id=i*ncw+j;
}
}
result.addActiveBoxContent(ab);
}
}
return result;
}
public void checkCells(){
int shaperCells=getShaper().getNumCells();
int existingCells=activeBoxContentArray.size();
if(existingCells>shaperCells){
while(activeBoxContentArray.size()>shaperCells){
activeBoxContentArray.remove(activeBoxContentArray.size()-1);
}
}
else if(shaperCells>existingCells){
for(int i=existingCells; i<shaperCells; i++){
ActiveBoxContent ab=getActiveBoxContent(i);
ab.id=defaultIdValue;
}
}
}
public static final String ELEMENT_NAME="cells";
public static final String ROWS="rows", COLUMNS="columns", COLS="cols";
public static final String CELL_WIDTH="cellWidth", CELL_HEIGHT="cellHeight",
BORDER="border", IMAGE="image", IDS="ids";
public org.jdom.Element getJDomElement(){
org.jdom.Element e=new org.jdom.Element(ELEMENT_NAME);
if(ncw>0 || nch>0){
e.setAttribute(ROWS, Integer.toString(nch));
e.setAttribute(COLS, Integer.toString(ncw));
}
if(imgName==null && (w!=0 || h!=0)){
e.setAttribute(CELL_WIDTH, Double.toString(w));
e.setAttribute(CELL_HEIGHT, Double.toString(h));
}
e.setAttribute(BORDER, JDomUtility.boolString(border));
if(imgName!=null){
e.setAttribute(IMAGE, imgName);
}
if(bb!=null){
e.addContent(bb.getJDomElement());
}
if(shaper!=null){
e.addContent(shaper.getJDomElement());
}
switch(testCellContents()){
case ActiveBoxContent.EMPTY_CELL:
// write nothing
break;
case ActiveBoxContent.ONLY_ID:
StringBuilder sb=new StringBuilder();
for(int i=0; i<activeBoxContentArray.size(); i++)
sb.append(getActiveBoxContent(i).id).append(" ");
e.addContent(new org.jdom.Element(IDS).addContent(sb.substring(0).trim()));
break;
default:
for(int i=0; i<activeBoxContentArray.size(); i++)
e.addContent(getActiveBoxContent(i).getJDomElement());
}
return e;
}
public int testCellContents(){
int result=ActiveBoxContent.EMPTY_CELL;
for(int i=0; i<activeBoxContentArray.size(); i++){
int r=getActiveBoxContent(i).testCellContents();
if(r>result){
result=r;
if(r>ActiveBoxContent.ONLY_ID)
break;
}
}
return result;
}
public static ActiveBagContent getActiveBagContent(org.jdom.Element e, MediaBag mediaBag) throws Exception{
ActiveBagContent abc=new ActiveBagContent();
abc.setProperties(e, mediaBag);
return abc;
}
public void setProperties(org.jdom.Element e, Object aux) throws Exception{
JDomUtility.checkName(e, ELEMENT_NAME);
MediaBag mediaBag=(MediaBag)aux;
org.jdom.Element child;
// Bug in JClic beta 1: "columns" is number of rows, and "rows" is number of columns.
// Corrected in beta 2: If "cols" is specified, "rows" are rows and "cols" are columns.
int k=JDomUtility.getIntAttr(e, COLS, -1);
if(k>=0){
ncw=k;
nch=JDomUtility.getIntAttr(e, ROWS, nch);
}
else{
ncw=JDomUtility.getIntAttr(e, ROWS, ncw);
nch=JDomUtility.getIntAttr(e, COLUMNS, nch);
}
activeBoxContentArray.ensureCapacity(Math.max(12, ncw*nch));
w=JDomUtility.getDoubleAttr(e, CELL_WIDTH, w);
h=JDomUtility.getDoubleAttr(e, CELL_HEIGHT, h);
border=JDomUtility.getBoolAttr(e, BORDER, border);
imgName=FileSystem.stdFn(e.getAttributeValue(IMAGE));
if((child=e.getChild(BoxBase.ELEMENT_NAME))!=null)
setBoxBase(BoxBase.getBoxBase(child));
if((child=e.getChild(Shaper.ELEMENT_NAME))!=null)
setShaper(Shaper.getShaper(child));
Iterator itr = e.getChildren(ActiveBoxContent.ELEMENT_NAME).iterator();
if(itr.hasNext())
while (itr.hasNext()){
child=((org.jdom.Element)itr.next());
addActiveBoxContent(ActiveBoxContent.getActiveBoxContent(child, mediaBag));
}
else{
child=e.getChild(IDS);
int[] v;
if(child!=null)
if((v=JDomUtility.stringToIntArray(child.getText()))!=null)
for(int i=0; i<v.length; i++)
getActiveBoxContent(i).id=v[i];
}
if(imgName!=null){
if(mediaBag!=null && mediaBag.getProject().getBridge()!=null)
setImgContent(mediaBag.getImageElement(imgName), true);
}
// Todo: check for empty-content
int n=activeBoxContentArray.size();
if(n>0){
boolean empty=true;
for(int i=0; i<n; i++){
ActiveBoxContent bxc=getActiveBoxContent(i);
if(bxc.id!=-1 || bxc.item!=-1 || !bxc.isEmpty()){
empty=false;
break;
}
}
if(empty){
for(int i=0; i<n; i++)
getActiveBoxContent(i).id=i;
}
}
}
public static void listReferences(org.jdom.Element e, Map<String, String> map){
String s=e.getAttributeValue(IMAGE);
if(s!=null)
map.put(s, Constants.MEDIA_OBJECT);
Iterator itr = e.getChildren(ActiveBoxContent.ELEMENT_NAME).iterator();
while(itr.hasNext())
ActiveBoxContent.listReferences((org.jdom.Element)itr.next(), map);
}
public Shaper getShaper(){
if(shaper==null)
setShaper(new Rectangular(ncw, nch));
return shaper;
}
public void setShaper(Shaper sh){
shaper=sh;
}
public void addActiveBoxContent(ActiveBoxContent ab){
activeBoxContentArray.add(ab);
if(ncw==0 || nch==0){
ncw=1;
nch=1;
}
}
public ActiveBoxContent getActiveBoxContent(int i){
if(i>=activeBoxContentArray.size()){
for(int j=activeBoxContentArray.size(); j<=i; j++)
activeBoxContentArray.add(new ActiveBoxContent());
}
return (ActiveBoxContent)activeBoxContentArray.get(i);
}
public ActiveBoxContent getActiveBoxContentWith(int id, int item){
ActiveBoxContent result=null;
for(int i=0; i<activeBoxContentArray.size(); i++){
ActiveBoxContent abxcnt=(ActiveBoxContent)activeBoxContentArray.get(i);
if(abxcnt.id==id && abxcnt.item==item){
result=abxcnt;
break;
}
}
return result;
}
public void deleteActiveBoxContentWith(int id, int item){
ActiveBoxContent abc=getActiveBoxContentWith(id, item);
if(abc!=null){
activeBoxContentArray.remove(abc);
for(int i=0; i<activeBoxContentArray.size(); i++){
abc=(ActiveBoxContent)activeBoxContentArray.get(i);
if(abc.id==id && abc.item>item)
abc.item--;
}
}
}
public void insertActiveBoxContentWith(int id, int item){
ActiveBoxContent abc=getActiveBoxContentWith(id, item);
int index=activeBoxContentArray.indexOf(abc);
for(int i=0; i<activeBoxContentArray.size(); i++){
abc=(ActiveBoxContent)activeBoxContentArray.get(i);
if(abc.id==id && abc.item>=item)
abc.item++;
}
abc=new ActiveBoxContent();
//abc.setTextContent("-");
abc.id=id;
abc.item=item;
activeBoxContentArray.add(index+1, abc);
}
public int indexOf(ActiveBoxContent cnt){
int result=-1;
for(int i=0; i<activeBoxContentArray.size(); i++){
if(activeBoxContentArray.get(i)==cnt){
result=i;
break;
}
}
return result;
}
public void setActiveBoxContentAt(ActiveBoxContent ab, int index){
if(index>=0){
getActiveBoxContent(index);
activeBoxContentArray.set(index, ab);
}
}
public void setImgContent(MediaBagElement mbe, boolean roundSizes) throws Exception{
setImgContent(mbe, getShaper(), roundSizes);
}
public void setImgContent(MediaBagElement mbe, Shaper sh) throws Exception{
setImgContent(mbe, sh, false);
}
public void setImgContent(MediaBagElement mbe, Shaper sh, boolean roundSizes) throws Exception{
setShaper(sh);
ncw=shaper.getNumColumns();
nch=shaper.getNumRows();
if(mbe!=null){
img=mbe.getImage();
imgName=mbe.getName();
w=-1; h=-1;
while(true){
w=((double)img.getWidth(null))/ncw;
h=((double)img.getHeight(null))/nch;
if(w>=0 && h>=0)
break;
Thread.sleep(50);
}
if(roundSizes){
w=(double)((int)w);
h=(double)((int)h);
}
if(w<1 || h<1)
throw new Exception("Invalid image!");
}
else{
img=null;
imgName=null;
w=Math.max(w, 10);
h=Math.max(h, 10);
}
Rectangle2D.Double r=new Rectangle2D.Double(0, 0, w*ncw, h*nch);
activeBoxContentArray.ensureCapacity(shaper.getNumCells());
for(int i=0; i<shaper.getNumCells(); i++){
getActiveBoxContent(i).setImgContent(img, shaper.getShape(i, r));
}
if(shaper.hasRemainder()){
backgroundContent=new ActiveBoxContent();
backgroundContent.setImgContent(img, shaper.getRemainderShape(r));
}
}
public void setTextContent(String[] txt, int setNcw, int setNch){
ncw=Math.max(1, setNcw);
nch=Math.max(1, setNch);
int n=ncw*nch;
activeBoxContentArray.ensureCapacity(n);
for(int i=0; i<n; i++){
getActiveBoxContent(i).setTextContent(((i>=txt.length || txt[i]==null)
? ""
: txt[i]));
}
}
public boolean hasImg(){
return img!=null;
}
public double getTotalWidth(){
return w*ncw;
}
public double getTotalHeight(){
return h*nch;
}
public int getNumCells(){
return activeBoxContentArray.size();
}
public boolean isEmpty(){
return activeBoxContentArray.isEmpty();
}
public void prepareMedia(PlayStation ps){
for(int i=0; i<activeBoxContentArray.size(); i++){
getActiveBoxContent(i).prepareMedia(ps);
}
if(img!=null && ps.getOptions().getBoolean(Constants.PRE_DRAW_IMAGES)){
Graphics g=ps.getComponent().getGraphics();
g.drawImage(img, 0, 0, 0, 0, ps.getComponent());
}
}
public void setBoxBase(BoxBase boxBase){
bb=boxBase;
}
public void setIds(int[] ids){
for(int i=0; i<activeBoxContentArray.size(); i++)
if(i<ids.length)
getActiveBoxContent(i).id=ids[i];
}
public void setAllIdsTo(int id){
for(int i=0; i<activeBoxContentArray.size(); i++)
getActiveBoxContent(i).id=id;
}
public void avoidAllIdsNull(int maxId){
boolean allIdsNull=true;
int numCells=activeBoxContentArray.size();
for(int i=0; i<numCells; i++){
if(getActiveBoxContent(i).id!=-1){
allIdsNull=false;
break;
}
}
if(allIdsNull){
maxId=Math.max(1, maxId);
for(int i=0; i<numCells; i++){
getActiveBoxContent(i).id=i%maxId;
}
}
}
public void copyStyleTo(ActiveBagContent abc){
if(abc!=null){
abc.setBoxBase(bb);
abc.border=border;
}
}
}