/* * File : Skin.java * Created : 11-oct-2001 16:09 * 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.skins; import edu.xtec.jclic.*; import edu.xtec.jclic.boxes.*; import edu.xtec.jclic.fileSystem.FileSystem; import edu.xtec.jclic.misc.Utils; import edu.xtec.util.*; import java.awt.*; import java.awt.event.*; import java.io.InputStream; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import javax.swing.*; /** * * @author Francesc Busquets (fbusquets@xtec.cat) * @version 13.09.10 */ public abstract class Skin extends JPanel implements ProgressInputStream.ProgressInputStreamListener{ public static final int DEFAULT_PROGRESS_WAKE_ON=1000; public static final String RESOURCE_FOLDER="skins"; public static final String RESOURCE_LIST_FILE="listskins.properties"; public static final int MAIN=0, AUX=1, MEM=2, NUM_MSG_AREAS=3; public static final String[] msgAreaNames={"main", "aux", "mem"}; public String name; public String fileName; protected AbstractButton[] buttons = new AbstractButton[Constants.NUM_ACTIONS]; protected Counter [] counters = new Counter[Constants.NUM_COUNTERS]; protected ActiveBox[] msgArea = new ActiveBox[NUM_MSG_AREAS]; protected Component player; protected PlayStation ps; protected ActiveBox msgBox; long mem; private static int waitCursorCount; protected boolean readyToPaint; public JDialog currentHelpWindow, currentAboutWindow; protected int progressMax, progress; protected boolean hasProgress, progressActive; protected long progressStartTime=0L; protected static HashSet<Skin> skinStack=new HashSet<Skin>(); /** Creates new Skin */ protected Skin() { super(); name=null; fileName=null; setEnabled(false); //setDoubleBuffered(true); readyToPaint=false; setLayout(null); player=null; ps=null; currentHelpWindow=null; currentAboutWindow=null; progress=0; progressMax=100; progressActive=false; hasProgress=false; skinStack.add(this); enableEvents(AWTEvent.MOUSE_EVENT_MASK); } public void emptySkinStack(){ skinStack=new HashSet<Skin>(); } public void attach(Component setPlayer){ if(player!=null) detach(); player=setPlayer; add(player); /* if(player instanceof ActionListener) for(int i=0; i<NUM_BUTTONS; i++) if(buttons[i]!=null) buttons[i].addActionListener((ActionListener)player); */ setWaitCursor(); setEnabled(true); revalidate(); } public void detach(){ if(player!=null){ remove(player); /* if(player instanceof ActivityContainer) for(int i=0; i<ActivityContainer.NUM_ACTIONS; i++){ if(buttons[i]!=null){ //buttons[i].removeActionListener((ActionListener)player); //buttons[i].removeActionListener(((ActivityContainer)player).getAction(i)); //buttons[i].setAction(null); } } */ player=null; } if(currentHelpWindow!=null) currentHelpWindow.setVisible(false); if(currentAboutWindow!=null) currentAboutWindow.setVisible(false); setEnabled(false); } public static final String ELEMENT_NAME="skin"; public static final String INTERNAL_SKIN_PREFIX="@"; public static final String NAME="name"; public static Skin getSkin(String skinName, FileSystem fs, PlayStation ps) throws Exception{ Iterator it=skinStack.iterator(); while(it.hasNext()){ Skin s=(Skin)it.next(); if(s!=null && skinName.equals(s.fileName) && ps.equals(s.ps)) return s; } org.jdom.Element e; if(skinName.startsWith(INTERNAL_SKIN_PREFIX)){ e=FileSystem.getXMLDocument(ResourceManager.getResourceAsStream(RESOURCE_FOLDER+"/"+skinName.substring(INTERNAL_SKIN_PREFIX.length()))).getRootElement(); fs=null; } else e=fs.getXMLDocument(skinName).getRootElement(); JDomUtility.checkName(e, ELEMENT_NAME); Class skinClass=Class.forName(JDomUtility.getClassName(e)); Skin sk=(Skin)skinClass.newInstance(); sk.name=e.getAttributeValue(NAME); sk.fileName=skinName; sk.ps=ps; sk.setProperties(e, fs); return sk; } protected abstract void setProperties(org.jdom.Element e, FileSystem fs) throws Exception; @Override public void paintComponent(Graphics g){ Graphics2D g2=(Graphics2D)g; RenderingHints rh=g2.getRenderingHints(); if(player!=null){ g2.setRenderingHints(Constants.DEFAULT_RENDERING_HINTS); } render(g2, g2.getClipBounds()); if(rh!=null) g2.setRenderingHints(rh); } public abstract void render(Graphics2D g2, Rectangle clip); @Override protected void processEvent(AWTEvent e) { if (ps != null && e instanceof MouseEvent) { if (e.getID() == MouseEvent.MOUSE_CLICKED) { Iterator it = getActiveBoxes(); while (it.hasNext()) { ActiveBox ab = (ActiveBox) it.next(); if (ab.contains(((MouseEvent) e).getPoint()) && ab.getContent().mediaContent != null) { ps.stopMedia(ab.getContent().mediaContent.level); ab.playMedia(ps); } } } } super.processEvent(e); } protected Iterator<ActiveBox> getActiveBoxes(){ ArrayList<ActiveBox> v=new ArrayList<ActiveBox>(); if(msgBox!=null) v.add(msgBox); return v.iterator(); } public void setProgressMax(int max){ progressMax=max; } public void setProgressValue(int value){ progress=value; } public void setProgressName(String name){ setSystemMessage(null, name==null ? null : ps.getMsg("LOADING_FILE")+" "+FileSystem.getFileNameOf(name)); } public void startProgress(String name){ progressStartTime=System.currentTimeMillis(); setProgressValue(0); progressActive=true; } public void endProgress(){ progressActive=false; } public InputStream getProgressInputStream(InputStream is, int expectedLength, String fName){ InputStream result; if(hasProgress && !progressActive){ ProgressInputStream pi=new ProgressInputStream(is, expectedLength, fName); pi.addProgressInputStreamListener(this); result=pi; } else{ result=is; } return result; } public ActiveBox getMsgBox(){ return msgBox; } public Counter getCounter(int counterId){ return ( (counterId<0 || counterId >=Constants.NUM_COUNTERS) ? null : counters[counterId]); } public void enableCounter(int counterId, boolean bEnabled){ Counter counter=getCounter(counterId); if(counter!=null) counter.setEnabled(bEnabled); } public void resetAllCounters(boolean bEnabled){ for(int i=0; i<Constants.NUM_COUNTERS; i++) if(counters[i]!=null){ counters[i].setValue(0); counters[i].setCountDown(0); counters[i].setEnabled(bEnabled); } } public AbstractButton getButton(int buttonId){ return( (buttonId<0 || buttonId>=Constants.NUM_ACTIONS) ? null : buttons[buttonId]); } /* public void enableButton(int buttonId, boolean state){ AbstractButton button=getButton(buttonId); if(button!=null) button.setEnabled(state); } */ public Object[] getCurrentSettings(){ Object [] settings = new Object[4]; settings[0]=buttons; settings[1]=msgBox; settings[2]=counters; settings[3]=new Integer(waitCursorCount); return settings; } public void setCurrentSettings(Object[] settings){ if(settings.length>0 && settings[0]!=null){ AbstractButton[] buttonSettings=(AbstractButton[])settings[0]; for(int i=0; i<Constants.NUM_ACTIONS; i++){ if(i<buttonSettings.length && buttonSettings[i]!=null && buttons[i]!=null){ //buttons[i].setEnabled(buttonSettings[i].isEnabled()); buttons[i].setVisible(buttonSettings[i].isVisible()); } } } if(settings.length>1 && settings[1]!=null && msgBox!=null){ ActiveBox abSettings=(ActiveBox)settings[1]; msgBox.copyContent(abSettings); msgBox.setBoxBase((abSettings.getBoxBaseResolve())); } if(settings.length>2 && settings[2]!=null && counters!=null){ Counter[] counterSettings=(Counter[])settings[2]; for(int i=0; i<Constants.NUM_COUNTERS; i++){ if(i<counterSettings.length && counterSettings[i]!=null && counters[i]!=null){ counters[i].setEnabled(counterSettings[i].isEnabled()); counters[i].setValue(counterSettings[i].getValue()); } } } if(settings.length>3 && settings[3]!=null){ waitCursorCount=((Integer)settings[3]).intValue(); setWaitCursor(); } } protected void drawSlicedFrame(Graphics g, Rectangle dest, Rectangle source, Image img, int leftSlicer, int rightSlicer, int topSlicer, int bottomSlicer){ Rectangle rs=new Rectangle(); Rectangle rd=new Rectangle(); // first row rs.setBounds(source.x, source.y, leftSlicer, topSlicer); rd.setBounds(dest.x, dest.y, rs.width, rs.height); Utils.drawImage(g, img, rd, rs, this); rs.x+=leftSlicer; rs.width=rightSlicer-leftSlicer; rd.x+=leftSlicer; rd.width=dest.width-leftSlicer-(source.width-rightSlicer); Utils.tileImage(g, img, rd, rs, this); rs.x=source.x+rightSlicer; rs.width=source.width-rightSlicer; rd.x=dest.x+dest.width-(source.width-rightSlicer); rd.width=rs.width; Utils.drawImage(g, img, rd, rs, this); // second row rs.setBounds(source.x, source.y+topSlicer, leftSlicer, bottomSlicer-topSlicer); rd.setBounds(dest.x, dest.y+topSlicer, leftSlicer, dest.height-topSlicer-(source.height-bottomSlicer)); Utils.tileImage(g, img, rd, rs, this); rs.x+=leftSlicer; rs.width=rightSlicer-leftSlicer; rd.x+=leftSlicer; rd.width=dest.width-leftSlicer-(source.width-rightSlicer); Utils.tileImage(g, img, rd, rs, this); rs.x=source.x+rightSlicer; rs.width=source.width-rightSlicer; rd.x=dest.x+dest.width-(source.width-rightSlicer); rd.width=rs.width; Utils.tileImage(g, img, rd, rs, this); // third row rs.setBounds(source.x, source.y+bottomSlicer, leftSlicer, source.height-bottomSlicer); rd.setBounds(dest.x, dest.y+dest.height-(source.height-bottomSlicer), rs.width, rs.height); Utils.drawImage(g, img, rd, rs, this); rs.x+=leftSlicer; rs.width=rightSlicer-leftSlicer; rd.x+=leftSlicer; rd.width=dest.width-leftSlicer-(source.width-rightSlicer); Utils.tileImage(g, img, rd, rs, this); rs.x=source.x+rightSlicer; rs.width=source.width-rightSlicer; rd.x=dest.x+dest.width-(source.width-rightSlicer); rd.width=rs.width; Utils.drawImage(g, img, rd, rs, this); } public boolean hasMemMonitor(){ return msgArea[MEM]!=null; } public void setMem(long newMem){ mem=newMem; if(msgArea[MEM]!=null){ String s=new StringBuilder(Long.toString(mem/1000)).append(" Kb").substring(0); msgArea[MEM].setTextContent(s); } } public void setSystemMessage(String msg1, String msg2){ if(/*!isEnabled() ||*/ !isVisible()) return; if(msgArea[MAIN]!=null && msg1!=null){ msgArea[MAIN].setTextContent(msg1); //if(readyToPaint) // msgArea[MAIN].paintImmediatelly(); } if(msgArea[AUX]!=null){ msgArea[AUX].setTextContent(msg2==null ? "" : msg2); //if(readyToPaint) // msgArea[AUX].paintImmediatelly(); } } public void startAnimation(){ } public void stopAnimation(){ } public void setWaitCursor(boolean status){ if(status){ waitCursorCount++; } else{ waitCursorCount--; if(waitCursorCount<0){ waitCursorCount=0; } } setWaitCursor(); } public void setWaitCursor(){ setCursor( waitCursorCount>0 ? Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR) : /*Cursor.getDefaultCursor()*/ null); } public void showHelp(JComponent solution, String msg){ currentHelpWindow=new HelpWindow(this, solution, msg); currentHelpWindow.setVisible(true); currentHelpWindow=null; requestFocus(); } class HelpWindow extends ExtendedJDialog{ HelpWindow(Component parent, JComponent solution, String msg){ super(parent, ps.getMsg("help_window_caption"), true); getContentPane().setLayout(new BorderLayout()); if(solution!=null) getContentPane().add(solution, BorderLayout.CENTER); else{ JLabel lb=new JLabel(msg==null || msg.trim().length()==0 ? "?" : msg.trim()); getContentPane().add(lb, BorderLayout.NORTH); } JButton btClose=new JButton(ps.getMsg("help_window_close_button"), ResourceManager.getImageIcon("icons/exit_small.gif")); btClose.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ setVisible(false); } }); getContentPane().add(btClose, BorderLayout.SOUTH); //setLocationRelativeTo(Skin.this); pack(); Point p=null; if(solution!=null){ p=(Point)solution.getClientProperty(HelpActivityComponent.PREFERRED_LOCATION); if(p!=null){ p=new Point(p); int dx=(getWidth()-getContentPane().getWidth())/2; int dy=getHeight()-getContentPane().getHeight()-dx; p.translate(-dx, -dy); } } if(p==null) p=parent.getLocationOnScreen(); setLocation(p); } } public AboutWindow buildAboutWindow(){ return new AboutWindow(this, ps, new Dimension(500, 400)); } public void showAboutWindow(AboutWindow aw){ currentAboutWindow=aw; currentAboutWindow.setVisible(true); currentAboutWindow=null; requestFocus(); } @Override public void requestFocus(){ if(player!=null) player.requestFocus(); } public static String[] getSystemSkinList(boolean withEmptyEntry){ ArrayList<String> v=new ArrayList<String>(); java.util.Properties prop=new java.util.Properties(); try{ prop.load(ResourceManager.getResourceAsStream(RESOURCE_FOLDER+"/"+RESOURCE_LIST_FILE)); } catch(Exception e){ System.err.println("Unable to open "+ResourceManager.RESOURCE_ROOT+RESOURCE_FOLDER+"/"+RESOURCE_LIST_FILE+":\n"+e); } if(withEmptyEntry) v.add(""); for(java.util.Enumeration e=prop.propertyNames(); e.hasMoreElements();){ String key=(String)e.nextElement(); String value="@"+prop.getProperty(key).trim(); v.add(value); } if(v.size()>0) return (String[])v.toArray(new String[v.size()]); else return new String[0]; } }