/*
* File : Order.java
* Created : 24-oct-2001 17:04
* 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.media.EventSounds;
import edu.xtec.jclic.project.JClicProject;
import edu.xtec.util.Actions;
import edu.xtec.util.JDomUtility;
import java.awt.AWTEvent;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.*;
/**
*
* @author Francesc Busquets (fbusquets@xtec.cat)
* @version 13.09.16
*/
public class Order extends TextActivityBase {
public static final int ORDER_WORDS=0, ORDER_PARAGRAPHS=1;
protected boolean amongParagraphs;
protected int type;
//boolean evalOnTheFly;
protected Evaluator ev;
/** Creates new Order */
public Order(JClicProject project) {
super(project);
//evalOnTheFly=false;
amongParagraphs=false;
setType(ORDER_WORDS);
hasCheckButton=true;
checkButtonText="";
ev=new BasicEvaluator(project);
}
public static final String[] TYPES={"orderWords", "orderParagraphs"};
public static final String AMONG_PARAGRAPHS="amongParagraphs";
@Override
public org.jdom.Element getJDomElement(){
org.jdom.Element e=super.getJDomElement();
e.setAttribute(TYPE, TYPES[type]);
if(amongParagraphs)
e.setAttribute(AMONG_PARAGRAPHS, JDomUtility.boolString(amongParagraphs));
e.addContent(ev.getJDomElement());
return e;
}
@Override
public void setProperties(org.jdom.Element e, Object aux) throws Exception{
super.setProperties(e, aux);
//evalOnTheFly=!hasCheckButton;
setType(JDomUtility.getStrIndexAttr(e, TYPE, TYPES, type));
if(type==ORDER_WORDS)
amongParagraphs=JDomUtility.getBoolAttr(e, AMONG_PARAGRAPHS, amongParagraphs);
ev=Evaluator.getEvaluator(e.getChild(Evaluator.ELEMENT_NAME), project);
}
@Override
public void setProperties(edu.xtec.jclic.clic3.Clic3Activity c3a) throws Exception{
super.setProperties(c3a);
((BasicEvaluator)ev).setProperties(c3a);
setType(c3a.puzMode==edu.xtec.jclic.clic3.Clic3.BPARAGRAFS ? ORDER_PARAGRAPHS : ORDER_WORDS);
amongParagraphs=c3a.brPar;
//evalOnTheFly=!hasCheckButton;
//evalOnTheFly=c3a.avCont;
//if(evalOnTheFly)
// hasCheckButton=false;
}
@Override
public Activity.Panel getActivityPanel(PlayStation ps) {
return new Panel(ps);
}
/** Getter for property type.
* @return Value of property type.
*/
public int getType() {
return type;
}
@Override
public boolean hasRandom(){
return true;
}
@Override
public boolean shuffleAlways(){
return true;
}
/** Setter for property type.
* @param type New value of property type.
*/
public void setType(int type) {
this.type = (type==ORDER_WORDS ? ORDER_WORDS : ORDER_PARAGRAPHS);
tad.setTargetType(type==ORDER_WORDS ? TextActivityDocument.TT_WORD : TextActivityDocument.TT_PARAGRAPH);
}
class Panel extends TextActivityBase.Panel {
TextActivityDocument playDoc;
int nActions;
TargetMarker anchor, cursor;
protected Panel(PlayStation ps){
super(ps);
playDoc=null;
nActions=0;
}
@Override
protected void initDocument() throws Exception{
if(tad!=null){
playing=false;
playDoc=new TextActivityDocument(styleContext);
tad.cloneDoc(playDoc, false, false, false);
for(int i=0; i<playDoc.tmb.size(); i++){
playDoc.tmb.getElement(i).target=new TextTarget();
playDoc.tmb.getElement(i).target.answer=new String[]{playDoc.tmb.getElement(i).getCurrentText()};
}
if(playDoc.tmb.size()>1){
for(int i=0; i<5; i++){
if(shuffle()!=playDoc.tmb.size())
break;
}
}
pane.setStyledDocument(playDoc);
playDoc.attachTo(pane, Order.Panel.this);
pane.setEditable(false);
pane.requestFocus();
bc=new edu.xtec.jclic.boxes.BoxConnector(pane);
nActions=0;
}
}
private int shuffle(){
if(playDoc==null || playDoc.tmb.size()<2)
return 0;
TargetMarkerBag tmb=playDoc.tmb;
int k=tmb.size();
int[] p=tmb.getParagragraphOffsets();
int[] p2=new int[k];
int k2;
for(k2=0; k2<k; k2++)
p2[k2]=k2;
int t1;
int t2=0;
java.util.Random rnd=new java.util.Random();
for(int i=0; i<shuffles; i++){
t1=rnd.nextInt(k);
if(type==ORDER_WORDS && !amongParagraphs){
k2=0;
for(int j=0; j<k; j++){
if(j!=t1 && p[j]==p[t1])
p2[k2++]=j;
}
}
if(k2>0){
for(int c=0; c<300; c++){
t2=p2[rnd.nextInt(k2)];
if(t2!=t1)
break;
}
if(t1!=t2)
tmb.swapTargets(tmb.getElement(t1), tmb.getElement(t2));
}
}
return tmb.checkTargets(ev);
}
@Override
protected TextActivityPane buildPane(){
//OrderPane p=new OrderPane(this);
OrderPane p=new OrderPane();
p.setActions();
return p;
}
class OrderPane extends TextActivityPane{
//public OrderPane(Order act){
protected OrderPane(){
super(Order.Panel.this);
enableEvents(AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK);
}
@Override
public boolean processMouse(MouseEvent e){
if(!super.processMouse(e) || bc==null || !playing)
return false;
switch(e.getID()){
case MouseEvent.MOUSE_PRESSED:
int p=viewToModel(e.getPoint());
if(p>=0){
playEvent(EventSounds.CLICK);
TargetMarker tm=playDoc.tmb.getElementByOffset(p, false);
if(tm!=null){
setTargetCursor(tm);
if(bc.active){
bc.end();
if(cursor==anchor){
setTargetAnchor(null);
setTargetCursor(tm);
}
else{
swapTargets(anchor, cursor);
}
}
else{
setTargetAnchor(tm);
bc.begin(e.getPoint());
}
}
else{
bc.end();
setTargetAnchor(null);
}
}
break;
case MouseEvent.MOUSE_MOVED:
case MouseEvent.MOUSE_DRAGGED:
if(bc.active)
bc.moveTo(e.getPoint());
break;
}
return false;
}
public boolean initKeyAction(){
if(!playing)
return false;
if(bc.active)
bc.end();
if(cursor==null){
setTargetCursor(playDoc.tmb.getElement(0));
return false;
}
return true;
}
// Actions
AbstractAction forwardAction=new AbstractAction(DefaultEditorKit.forwardAction){
public void actionPerformed(ActionEvent e){
nextTargetAction.actionPerformed(e);
}
};
AbstractAction backwardAction=new AbstractAction(DefaultEditorKit.backwardAction){
public void actionPerformed(ActionEvent e){
prevTargetAction.actionPerformed(e);
}
};
AbstractAction nextTargetAction=new AbstractAction("next-target"){
public void actionPerformed(ActionEvent e){
if(initKeyAction()){
setTargetCursor(playDoc.tmb.getNextTarget(cursor));
}
}
};
AbstractAction prevTargetAction=new AbstractAction("prev-target"){
public void actionPerformed(ActionEvent e){
if(initKeyAction()){
setTargetCursor(playDoc.tmb.getPrevTarget(cursor));
}
}
};
AbstractAction insertBreakAction=new AbstractAction(DefaultEditorKit.insertBreakAction){
public void actionPerformed(ActionEvent e){
if(initKeyAction()){
if(anchor==null)
setTargetAnchor(cursor);
else
swapTargets(anchor, cursor);
}
}
};
AbstractAction insertTabAction=new AbstractAction(DefaultEditorKit.insertTabAction){
public void actionPerformed(ActionEvent e){
if((e.getModifiers() & ActionEvent.SHIFT_MASK)!=0)
prevTargetAction.actionPerformed(e);
else
nextTargetAction.actionPerformed(e);
}
};
AbstractAction beginAction=new AbstractAction(DefaultEditorKit.beginAction){
public void actionPerformed(ActionEvent e){
if(initKeyAction()){
setTargetCursor(playDoc.tmb.getElement(0));
}
}
};
AbstractAction endAction=new AbstractAction(DefaultEditorKit.endAction){
public void actionPerformed(ActionEvent e){
if(initKeyAction()){
setTargetCursor(playDoc.tmb.getElement(playDoc.tmb.size()-1));
}
}
};
AbstractAction upAction=new AbstractAction(DefaultEditorKit.upAction){
public void actionPerformed(ActionEvent e){
prevTargetAction.actionPerformed(e);
}
};
AbstractAction downAction=new AbstractAction(DefaultEditorKit.downAction){
public void actionPerformed(ActionEvent e){
nextTargetAction.actionPerformed(e);
}
};
protected void setActions(){
java.util.Map<String, Object[]> actionKeys=Actions.getActionKeys(this);
ActionMap am=new ActionMap();
am.setParent(getActionMap());
setActionMap(am);
//Originals:
Actions.mapTraceAction(this, actionKeys, DefaultEditorKit.beepAction);
Actions.mapTraceAction(this, actionKeys, "requestFocus");
Actions.mapTraceAction(this, actionKeys, "toggle-componentOrientation");
//Derivats:
Actions.mapAction(this, actionKeys, insertBreakAction);
Actions.mapAction(this, actionKeys, insertTabAction);
Actions.mapAction(this, actionKeys, forwardAction);
Actions.mapAction(this, actionKeys, backwardAction);
Actions.mapAction(this, actionKeys, beginAction);
Actions.mapAction(this, actionKeys, endAction);
Actions.mapAction(this, actionKeys, upAction);
Actions.mapAction(this, actionKeys, downAction);
Actions.mapAction(this, actionKeys, nextTargetAction);
Actions.mapAction(this, actionKeys, prevTargetAction);
am.setParent(null);
getInputMap().put(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_TAB, java.awt.Event.SHIFT_MASK), insertTabAction.getValue(Action.NAME));
}
}
protected void setTargetAnchor(TargetMarker tm){
if(anchor!=null)
playDoc.applyStyleToTarget(anchor, TextActivityDocument.TARGET, false, true);
anchor=tm;
if(anchor!=null)
playDoc.applyStyleToTarget(anchor, TextActivityDocument.TARGET, true, true);
}
protected void setTargetCursor(TargetMarker tm){
if(tm!=null && tm==anchor){
cursor=tm;
return;
}
if(cursor!=null){
if(cursor!=anchor)
playDoc.applyStyleToTarget(cursor, TextActivityDocument.TARGET, false, true);
}
cursor=tm;
if(cursor!=null)
playDoc.applyStyleToTarget(cursor, null, true, true);
}
protected void swapTargets(TargetMarker src, TargetMarker dest){
if(src==dest || !playing || playDoc==null)
return;
setTargetAnchor(null);
TargetMarkerBag tmb=playDoc.tmb;
tmb.swapTargets(src, dest);
src.checkText(ev);
boolean ok=dest.checkText(ev);
nActions++;
//if(evalOnTheFly){
if(!hasCheckButton){
int solvedTargets=tmb.countSolvedTargets();
ps.reportNewAction(getActivity(), ACTION_PLACE, src.getCurrentText(), Integer.toString(tmb.indexOf(dest)), ok, solvedTargets);
if(ok && solvedTargets==tmb.size()){
finishActivity(true);
}
else{
playEvent(ok ? EventSounds.ACTION_OK : EventSounds.ACTION_ERROR);
}
}
setTargetCursor(dest);
}
@Override
protected void doCheck(boolean fromButton){
if(playDoc==null || playDoc.tmb.size()==0)
return;
TargetMarkerBag tmb=playDoc.tmb;
if(bc.active)
bc.end();
for(int i=0; i<tmb.size(); i++){
TargetMarker tm=tmb.getElement(i);
playDoc.applyStyleToTarget(tm, tm.target.targetStatus==TextTarget.SOLVED ? TextActivityDocument.TARGET:TextActivityDocument.TARGET_ERROR, false, true);
}
int tagsSolved=tmb.countSolvedTargets();
ps.setCounterValue(SCORE_COUNTER, tagsSolved);
ps.setCounterValue(ACTIONS_COUNTER, nActions);
if(tagsSolved!=tmb.size()){
if(fromButton){
playEvent(EventSounds.FINISHED_ERROR);
pane.requestFocus();
}
}
else
finishActivity(true);
}
@Override
public void finishActivity(boolean result){
if(bc.active)
bc.end();
pane.setEnabled(false);
super.finishActivity(result);
}
}
}