/*
* File : WrittenAnswer.java
* Created : 09-may-2001 11:15
* 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.text;
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.MouseEvent;
import javax.swing.JTextField;
/**
*
* @author Francesc Busquets (fbusquets@xtec.cat)
* @version 13.08.28
*/
public class WrittenAnswer extends Activity implements ActiveBagContentKit.Compatible {
int nonAssignedCells;
boolean useIdAss;
/** Creates new WrittenAnswer */
public WrittenAnswer(JClicProject project) {
super(project);
boxGridPos=AB;
abc=new ActiveBagContent[3];
//for(int i=0; i<3; i++)
// abc[i]=null;
scramble[0]=false;
nonAssignedCells=0;
invAss=false;
useIdAss=true;
}
@Override
public void initNew(){
super.initNew();
abc[0]=ActiveBagContent.initNew(3, 2, 'A');
abc[1]=ActiveBagContent.initNew(3, 2, 'A');
}
protected static final String ANSWERS="answers", INVERSE="inverse";
@Override
public org.jdom.Element getJDomElement(){
org.jdom.Element ex;
if(abc[0]==null || abc[1]==null) return null;
org.jdom.Element e=super.getJDomElement();
e.addContent(abc[0].getJDomElement().setAttribute(ID, PRIMARY));
e.addContent(abc[1].getJDomElement().setAttribute(ID, ANSWERS));
if(abc[2]!=null)
e.addContent(abc[2].getJDomElement().setAttribute(ID, SOLVED_PRIMARY));
ex=new org.jdom.Element(SCRAMBLE);{
ex.setAttribute(TIMES, Integer.toString(shuffles));
ex.setAttribute(PRIMARY, JDomUtility.boolString(scramble[0]));
e.addContent(ex);
}
ex=new org.jdom.Element(LAYOUT);
ex.setAttribute(POSITION, LAYOUT_NAMES[boxGridPos]);
e.addContent(ex);
if(invAss)
e.setAttribute(INVERSE, JDomUtility.boolString(invAss));
return e;
}
@Override
public void setProperties(org.jdom.Element e, Object aux) throws Exception{
org.jdom.Element child;
super.setProperties(e, aux);
ActiveBagContent bag;
abc[2]=null;
java.util.Iterator itr = e.getChildren(ActiveBagContent.ELEMENT_NAME).iterator();
while (itr.hasNext()){
child=((org.jdom.Element)itr.next());
bag=ActiveBagContent.getActiveBagContent(child, project.mediaBag);
String id=JDomUtility.getStringAttr(child, ID, PRIMARY, false);
if(PRIMARY.equals(id))
abc[0]=bag;
else if(ANSWERS.equals(id))
abc[1]=bag;
else if(SOLVED_PRIMARY.equals(id))
abc[2]=bag;
}
if(abc[0]==null || abc[1]==null)
throw new IllegalArgumentException("WrittenAnswer without content!");
if((child=e.getChild(SCRAMBLE))!=null){
shuffles=JDomUtility.getIntAttr(child, TIMES, shuffles);
scramble[0]=JDomUtility.getBoolAttr(child, PRIMARY, scramble[0]);
}
if((child=e.getChild(LAYOUT))!=null)
boxGridPos=JDomUtility.getStrIndexAttr(child, POSITION, LAYOUT_NAMES, boxGridPos);
invAss=JDomUtility.getBoolAttr(e, INVERSE, invAss);
abc[0].avoidAllIdsNull(abc[1].getNumCells());
}
@Override
public void setProperties(edu.xtec.jclic.clic3.Clic3Activity c3a) throws Exception{
super.setProperties(c3a);
// Clic3 problem
c3a.nctxw=c3a.ncw;
c3a.nctxh=c3a.nch;
boxGridPos=c3a.graPos;
for(int i=0; i<2; i++){
abc[i]=c3a.createActiveBagContent(i);
abc[i].setBoxBase(c3a.getBoxBase(i));
}
scramble[0]=c3a.bar[0];
abc[2]=c3a.sol ? c3a.createActiveBagContent(2) : null;
abc[0].avoidAllIdsNull(abc[1].getNumCells());
}
public int getMinNumActions(){
if(abc[0]==null || abc[1]==null)
return 0;
if(invAss)
return abc[1].getNumCells();
else
return abc[0].getNumCells()-nonAssignedCells;
}
@Override
public boolean helpSolutionAllowed(){
return true;
}
@Override
public boolean hasRandom(){
return true;
}
@Override
public boolean needsKeyboard(){
return true;
}
public Activity.Panel getActivityPanel(PlayStation ps) {
return new Panel(ps);
}
class Panel extends Activity.Panel implements java.awt.event.ActionListener {
JTextField textField;
ActiveBoxBag[] bg=new ActiveBoxBag[2];
int currentCell;
boolean[] invAssCheck;
protected Panel(PlayStation ps){
super(ps);
for(int i=0; i<2; i++)
bg[i]=null;
currentCell=-1;
textField=null;
//<<
invAssCheck=null;
//>>
}
public void clear(){
for(int i=0; i<2; i++)
if(bg[i]!=null){
bg[i].end();
bg[i]=null;
}
textField=null;
}
@Override
public void buildVisualComponents() throws Exception{
if(firstRun)
super.buildVisualComponents();
ActiveBox bx;
currentCell=-1;
clear();
if(abc[0]!=null && abc[1]!=null){
if(acp!=null)
acp.generateContent(new ActiveBagContentKit(abc[0].nch, abc[0].ncw, abc, true), ps);
if(invAss){
invAssCheck=new boolean[abc[1].getNumCells()];
for(int i=0; i<invAssCheck.length; i++)
invAssCheck[i]=false;
}
bg[0]=ActiveBoxGrid.createEmptyGrid(null, this, margin, margin, abc[0]);
// Clic3 behavior!!!
double w=abc[1].w;
if(boxGridPos==AUB || boxGridPos==BUA)
w=abc[0].getTotalWidth();
bg[1]=new ActiveBoxGrid(null, this, margin, margin, w, abc[1].h, new edu.xtec.jclic.shapers.Rectangular(1, 1), abc[1].bb);
textField=new JTextField(200);
textField.setHorizontalAlignment(JTextField.CENTER);
bx=bg[1].getActiveBox(0);
bx.setInactive(false);
bx.hasHostedComponent=true;
bx.setHostedComponent(textField);
textField.addActionListener(this);
bg[0].setContent(abc[0], abc[2]);
currentCell=0;
bg[0].setDefaultIdAss();
nonAssignedCells=0;
for(int i=0; i<bg[0].getNumCells(); i++){
bx=bg[0].getActiveBox(i);
if(bx.idAss==-1){
nonAssignedCells++;
bx.switchToAlt(ps);
}
}
bg[0].setVisible(true);
bg[1].setVisible(true);
invalidate();
}
}
@Override
public void initActivity() throws Exception{
super.initActivity();
if(!firstRun)
buildVisualComponents();
else firstRun=false;
//setCounters(0, 0, 0);
setAndPlayMsg(MAIN, EventSounds.START);
//ps.setMsg(messages[MAIN]);
if(bg[0]!=null && bg[1]!=null){
if(scramble[0])
shuffle(new ActiveBoxBag[] {bg[0]}, true, true);
//ps.playMsg();
//if(messages[MAIN]==null || messages[MAIN].mediaContent==null)
// playEvent(EventSounds.START);
if(useOrder)
currentItem=bg[0].getNextItem(-1);
playing=true;
setCurrentCell(0);
}
}
public void render(Graphics2D g2, Rectangle dirtyRegion) {
for(int i=0; i<2; i++){
if(bg[i]!=null)
bg[i].update(g2, dirtyRegion, this);
}
}
public Dimension setDimension(Dimension preferredMaxSize){
return bg[0]==null || bg[1]==null || getSize().equals(preferredMaxSize)
? preferredMaxSize
: BoxBag.layoutDouble(preferredMaxSize, bg[0], bg[1], boxGridPos, margin);
}
private boolean checkInvAss(){
if(invAss==false || invAssCheck==null)
return false;
for(boolean b : invAssCheck)
if(!b)
return false;
return true;
}
private void setCurrentCell(int i){
ActiveBox bx;
boolean m=false;
if(!playing) return;
if(currentCell!=-1){
boolean ok=false;
bx=bg[0].getActiveBoxWithIdLoc(currentCell);
String src=bx.getDescription();
bx.setMarked(false);
//<<
//String txCheck=abc[1].getActiveBoxContent(bx.idOrder).text;
int id=bx.idAss;
String txCheck = (id>=0 ? abc[1].getActiveBoxContent(id).text : "");
//>>
String txAnswer=textField.getText().trim();
if(edu.xtec.util.StrUtils.compareMultipleOptions(txAnswer, txCheck, false)){
ok=true;
bx.idAss=-1;
// 29-mai-2007
// When in multiple-answer, fill-in textField with
// the first valid option:
if(txCheck.indexOf('|')>=0)
textField.setText((new java.util.StringTokenizer(txCheck, "|")).nextToken());
if(abc[2]!=null){
bx.switchToAlt(ps);
m=bx.playMedia(ps);
}
else
bx.clear();
if(invAss && id>=0 && id<invAssCheck.length){
invAssCheck[id]=true;
}
if(useOrder)
currentItem=bg[0].getNextItem(currentItem);
}
int cellsPlaced=bg[0].countCellsWithIdAss(-1);
if(txAnswer.length()>0){
ps.reportNewAction(getActivity(), ACTION_WRITE, src, txAnswer, ok, cellsPlaced);
}
if(ok && (checkInvAss() || cellsPlaced==bg[0].getNumCells())){
finishActivity(true);
textField.setEnabled(false);
return;
}
else if(!m && txAnswer.length()>0)
playEvent(ok ? EventSounds.ACTION_OK : EventSounds.ACTION_ERROR);
}
if(useOrder)
bx=(ActiveBox)bg[0].getBox(currentItem);
else
bx=bg[0].getActiveBoxWithIdLoc(i);
if(bx==null || bx.idAss==-1){
for(int j=0; j<bg[0].getNumCells(); j++){
bx=bg[0].getActiveBoxWithIdLoc(j);
if(bx.idAss!=-1) break;
}
if(bx!=null && bx.idAss==-1){
// error ?
finishActivity(false);
textField.setEnabled(false);
return;
}
}
// 29 - mai -2007
// Draw border only if it has more than one cell
if(bg[0].getNumCells()>1 && bx!=null)
bx.setMarked(true);
if(bx!=null)
currentCell=bx.idLoc;
textField.setText("");
textField.requestFocus();
if(bx!=null)
bx.playMedia(ps);
}
@Override
public void requestFocus(){
if(playing && textField!=null)
textField.requestFocus();
}
public void actionPerformed(java.awt.event.ActionEvent e){
if(playing && e.getSource()==textField && currentCell!=-1)
setCurrentCell(currentCell);
}
@Override
public void processMouse(MouseEvent e){
ActiveBox bx;
boolean m=false;
if(playing) switch(e.getID()){
case MouseEvent.MOUSE_PRESSED:
ps.stopMedia(1);
if((bx=bg[0].findActiveBox(e.getPoint()))!=null){
if(bx.getContent()!=null && bx.getContent().mediaContent==null)
playEvent(EventSounds.CLICK);
setCurrentCell(bx.idLoc);
}
break;
}
}
@Override
public void showHelp(){
if(!helpWindowAllowed() || bg[0]==null) return;
HelpActivityComponent hac=null;
if(showSolution){
hac=new HelpActivityComponent(this){
ActiveBoxBag abb=null;
String currentResponse="";
int cellsPlaced=bg[0].countCellsWithIdAss(-1);
public void render(Graphics2D g2, Rectangle dirtyRegion){
if(abb!=null) abb.update(g2, dirtyRegion, this);
}
@Override
public void init(){
currentResponse=textField.getText();
abb=(ActiveBoxBag)bg[0].clone();
abb.setContainer(this);
Dimension size=abb.getBounds().getSize();
abb.setBounds(DEFAULT_MARGIN, DEFAULT_MARGIN, size.width, size.height);
size.width+=2*DEFAULT_MARGIN;
size.height+=2*DEFAULT_MARGIN;
setPreferredSize(size);
setMaximumSize(size);
setMinimumSize(size);
Point p=(Point)getClientProperty(HelpActivityComponent.PREFERRED_LOCATION);
if(p!=null)
p.translate((int)bg[0].x-DEFAULT_MARGIN, (int)bg[0].y-DEFAULT_MARGIN);
}
@Override
public void end(){
super.end();
textField.setText(currentResponse);
}
@Override
public void processMouse(MouseEvent e){
ActiveBox bx;
if(abb!=null) switch(e.getID()){
case MouseEvent.MOUSE_PRESSED:
bx=abb.findActiveBox(e.getPoint());
if(bx!=null){
boolean m=bx.playMedia(ps);
String s=abc[1].getActiveBoxContent(bx.idOrder).text;
if(s!=null)
textField.setText(s.replace('|', ' '));
ps.reportNewAction(getActivity(), ACTION_HELP, bx.getDescription(), null, false, cellsPlaced);
if(!m)
playEvent(EventSounds.CLICK);
}
break;
case MouseEvent.MOUSE_RELEASED:
unmarkBox();
textField.setText("");
break;
}
}
};
hac.init();
}
if(ps.showHelp(hac, helpMsg))
ps.reportNewAction(getActivity(), ACTION_HELP, null, null, false, bg[0].countCellsWithIdAss(-1));
if(hac!=null)
hac.end();
}
}
}