/* * File : CrossWord.java * Created : 04-oct-2001 19:53 * 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.activities.textGrid; import edu.xtec.jclic.*; import edu.xtec.jclic.automation.ActiveBagContentKit; import edu.xtec.jclic.boxes.*; import edu.xtec.jclic.media.EventSounds; import edu.xtec.jclic.project.JClicProject; import edu.xtec.util.JDomUtility; import java.awt.*; import java.awt.event.*; import javax.swing.JToggleButton; /** * * @author Francesc Busquets (fbusquets@xtec.cat) * @version 13.08.29 */ public class CrossWord extends Activity implements ActiveBagContentKit.Compatible{ public static final int NO_ADVANCE=0, ADVANCE_RIGHT=1, ADVANCE_DOWN=2; public static final int LABEL_WIDTH=40; public boolean wildTransparent; public boolean upperCase; public boolean checkCase; /** Creates new CrossWords */ public CrossWord(JClicProject project) { super(project); boxGridPos=AB; abc=new ActiveBagContent[2]; wildTransparent=false; upperCase=true; checkCase=true; } @Override public void initNew(){ super.initNew(); abc[0]=ActiveBagContent.initNew(3, 1, -1, true, true, 200, 60); abc[1]=ActiveBagContent.initNew(3, 1, -1, true, true, 200, 60); tgc=TextGridContent.initNew(3, 3, 'A'); } public static final String ACROSS_CLUES="acrossClues", DOWN_CLUES="downClues", WILD_TRANSPARENT="wildTransparent", UPPERCASE="upperCase", CHECK_CASE="checkCase"; @Override public org.jdom.Element getJDomElement(){ org.jdom.Element child; if(tgc==null || abc[0]==null || abc[1]==null) return null; org.jdom.Element e=super.getJDomElement(); e.addContent(tgc.getJDomElement()); e.addContent(abc[0].getJDomElement().setAttribute(ID, ACROSS_CLUES)); e.addContent(abc[1].getJDomElement().setAttribute(ID, DOWN_CLUES)); child=new org.jdom.Element(LAYOUT); child.setAttribute(POSITION, LAYOUT_NAMES[boxGridPos]); if(wildTransparent) child.setAttribute(WILD_TRANSPARENT, JDomUtility.boolString(wildTransparent)); if(!upperCase) child.setAttribute(UPPERCASE, JDomUtility.boolString(upperCase)); if(!checkCase) child.setAttribute(CHECK_CASE, JDomUtility.boolString(checkCase)); e.addContent(child); return e; } @Override public void setProperties(org.jdom.Element e, Object aux) throws Exception{ org.jdom.Element child; super.setProperties(e, aux); if((child=e.getChild(TextGridContent.ELEMENT_NAME))==null) throw new IllegalArgumentException("CrossWord without TextGrid"); tgc=TextGridContent.getTextGridContent(child); java.util.Iterator it=e.getChildren(ActiveBagContent.ELEMENT_NAME).iterator(); while(it.hasNext()){ child=(org.jdom.Element)it.next(); ActiveBagContent bc=ActiveBagContent.getActiveBagContent(child, project.mediaBag); String id=JDomUtility.getStringAttr(child, ID, null, false); if(ACROSS_CLUES.equals(id)) abc[0]=bc; else if(DOWN_CLUES.equals(id)) abc[1]=bc; else throw new IllegalArgumentException("Unknown clues: "+id); } if(abc[0]==null || abc[1]==null) throw new IllegalArgumentException("CrossWord without H or V clues!"); if((child=e.getChild(LAYOUT))!=null){ boxGridPos=JDomUtility.getStrIndexAttr(child, POSITION, LAYOUT_NAMES, boxGridPos); wildTransparent=JDomUtility.getBoolAttr(child, WILD_TRANSPARENT, wildTransparent); upperCase=JDomUtility.getBoolAttr(child, UPPERCASE, upperCase); checkCase=JDomUtility.getBoolAttr(child, CHECK_CASE, checkCase); } } @Override public void setProperties(edu.xtec.jclic.clic3.Clic3Activity c3a) throws Exception{ super.setProperties(c3a); boxGridPos=c3a.graPos; tgc=new TextGridContent(); tgc.nch=c3a.nctxh; tgc.ncw=c3a.nctxw; tgc.w=c3a.txtCW; tgc.h=c3a.txtCH; //tgc.border=c3a.delim[1]; tgc.border=true; tgc.text=c3a.graTxt; tgc.bb=c3a.getBoxBase(0); for(int k=0; k<2; k++){ abc[k]=new ActiveBagContent(1,1); int i, j, l; for(i=0, l=0; i<c3a.tags[k].length; i++){ j=0; java.util.StringTokenizer st=new java.util.StringTokenizer(c3a.tags[k][i], ";"); while(st.hasMoreElements()){ ActiveBoxContent bc=abc[k].getActiveBoxContent(l++); c3a.setActiveBoxTextContent(bc, st.nextToken()); bc.id=i; bc.item=j++; } } abc[k].bb=c3a.getBoxBase(1); abc[k].ncw=1; abc[k].nch=i; //abc[k].w=200; abc[k].h=50; abc[k].w=200; abc[k].h=75; } } public int getMinNumActions(){ return (tgc==null ? 0 : tgc.getNumChars()-tgc.countWildChars()); } @Override public boolean helpSolutionAllowed(){ return false; } @Override public boolean needsKeyboard(){ return true; } public Activity.Panel getActivityPanel(PlayStation ps) { return new Panel(ps); } class Panel extends Activity.Panel implements ActionListener, FocusListener{ TextGrid grid; BoxBag bb; int advance; int numLetters; ActiveBox hClue, vClue; JToggleButton hClueBtn, vClueBtn; protected Panel(PlayStation ps){ super(ps); grid=null; bb=null; advance=NO_ADVANCE; numLetters=0; addFocusListener(this); } public void clear(){ if(grid!=null){grid.end();grid=null;} if(bb!=null){bb.end();bb=null;} } private BoxBag createBoxBag(int n){ BoxBag bxb=new BoxBag(null, this, null); SimpleBox sb=new SimpleBox(bxb, null, null); sb.setBounds(0, 0, LABEL_WIDTH, abc[n].h); sb.setBorder(true); JToggleButton tgbtn=new JToggleButton(edu.xtec.util.ResourceManager.getImageIcon(n== 0 ? "buttons/textright.png":"buttons/textdown.png")); tgbtn.addActionListener(this); javax.swing.border.Border border=tgbtn.getBorder(); sb.setHostedComponent(tgbtn); tgbtn.setBorder(border); bxb.addBox(sb); ActiveBox ab=new ActiveBox(bxb, null, n, new java.awt.geom.Rectangle2D.Double(LABEL_WIDTH, 0, abc[n].w, abc[n].h), null); bxb.addBox(ab); bxb.setBoxBase(abc[n].bb); if(n==0){ hClue=ab; hClueBtn=tgbtn; } else{ vClue=ab; vClueBtn=tgbtn; } return bxb; } @Override public void buildVisualComponents() throws Exception{ if(firstRun) super.buildVisualComponents(); clear(); if(acp!=null && abc!=null) acp.generateContent(new ActiveBagContentKit(0, 0, abc, false), ps); if(tgc!=null){ grid=TextGrid.createEmptyGrid(null, this, margin, margin, tgc, wildTransparent); //if(acp!=null) acp.generateContent(abc[0].nch, abc[0].ncw, abc, false, ac); bb=new BoxBag(null, this, null); BoxBag bxbh=createBoxBag(0); BoxBag bxbv=createBoxBag(1); if(boxGridPos==AUB || boxGridPos==BUA) bxbv.setLocation(bxbh.getWidth()+margin, 0); else bxbv.setLocation(0, bxbh.getHeight()+margin); bb.addBox(bxbh); bb.addBox(bxbv); grid.setVisible(true); bb.setVisible(true); invalidate(); } } @Override public void initActivity() throws Exception{ super.initActivity(); if(!firstRun) buildVisualComponents(); else firstRun=false; setAndPlayMsg(MAIN, EventSounds.START); //ps.setMsg(messages[MAIN]); if(grid!=null){ grid.setChars(tgc.text); numLetters=getMinNumActions(); grid.setCellAttributes(true, true); grid.setCursorEnabled(true); setCursorAt(0,0); advance=ADVANCE_RIGHT; hClueBtn.setSelected(true); requestFocus(); //ps.playMsg(); //if(messages[MAIN]==null || messages[MAIN].mediaContent==null) // playEvent(EventSounds.START); playing=true; } } public int getCurrentScore(){ return grid==null ? 0 : grid.countCoincidences(checkCase); } public void render(Graphics2D g2, Rectangle dirtyRegion) { if(grid!=null) grid.update(g2, dirtyRegion, this); if(bb!=null) bb.update(g2, dirtyRegion, this); } public Dimension setDimension(Dimension preferredMaxSize){ if(grid==null || bb==null || getSize().equals(preferredMaxSize)) return preferredMaxSize; else return BoxBag.layoutDouble(preferredMaxSize, grid, bb, boxGridPos, margin); } @Override public void processMouse(MouseEvent e){ Point p=e.getPoint(); if(playing) switch(e.getID()){ case MouseEvent.MOUSE_PRESSED: ps.stopMedia(1); if(grid.contains(p)){ Point pt=grid.getLogicalCoords(p); if(pt!=null){ setCursorAt(pt.x, pt.y); } } else if(hClue.contains(p)) hClue.playMedia(ps); else if(vClue.contains(p)) vClue.playMedia(ps); break; } } protected void moveCursor(int dx, int dy){ if(grid!=null){ grid.moveCursor(dx, dy, true); cursorPosChanged(); } } protected void setCursorAt(int x, int y){ grid.setCursorAt(x, y, true); cursorPosChanged(); } protected void cursorPosChanged(){ Point pt=grid.getCursor(); if(pt!=null && bb!=null){ Point items=grid.getItemFor(pt.x, pt.y); if(items!=null){ hClue.setContent(abc[0].getActiveBoxContentWith(pt.y, items.x)); vClue.setContent(abc[1].getActiveBoxContentWith(pt.x, items.y)); } } } @Override public void processKey(KeyEvent e){ if(playing && grid!=null) switch(e.getID()){ case KeyEvent.KEY_TYPED: Point cur=grid.getCursor(); char ch=e.getKeyChar(); if(ch>=0 && cur!=null){ if(upperCase) ch=Character.toUpperCase(ch); grid.setCharAt(cur.x, cur.y, ch); boolean ok=grid.isCellOk(cur.x, cur.y, checkCase); int r=getCurrentScore(); ps.reportNewAction(getActivity(), ACTION_WRITE, String.copyValueOf(new char[]{ch}), "X:"+cur.x+" Y:"+cur.y, ok, r); if(r==numLetters){ grid.setCursorEnabled(false); grid.stopCursorBlink(); finishActivity(true); } else{ //playEvent(ok ? EventSounds.ACTION_OK : EventSounds.ACTION_ERROR); playEvent(EventSounds.CLICK); if(advance==ADVANCE_RIGHT) moveCursor(1, 0); else if(advance==ADVANCE_DOWN) moveCursor(0, 1); } } break; case KeyEvent.KEY_PRESSED: int dx=0, dy=0; switch(e.getKeyCode()){ case KeyEvent.VK_RIGHT: dx=1; break; case KeyEvent.VK_LEFT: dx=-1; break; case KeyEvent.VK_DOWN: dy=1; break; case KeyEvent.VK_UP: dy=-1; break; } if(dx!=0 || dy!=0) moveCursor(dx, dy); break; } } public void focusGained(FocusEvent e){ if(playing && grid!=null) grid.startCursorBlink(); } public void focusLost(FocusEvent e){ if(grid!=null) grid.stopCursorBlink(); } public void actionPerformed(ActionEvent ev){ advance=NO_ADVANCE; if(ev.getSource().equals(hClueBtn)){ if(hClueBtn.isSelected()) advance=ADVANCE_RIGHT; vClueBtn.setSelected(false); } else if(ev.getSource().equals(vClueBtn)){ if(vClueBtn.isSelected()) advance=ADVANCE_DOWN; hClueBtn.setSelected(false); } requestFocus(); } } }