package testing; import java.awt.Color; import java.awt.Graphics; import java.awt.GraphicsEnvironment; import java.awt.Image; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.DataInputStream; import java.io.FileInputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.util.List; import java.util.Vector; import javax.swing.JFrame; import log.LogfileRow; import screens.ExperimentEndScreen; import screens.Screen; import screens.BeginScreen; import screens.TestCorrectScreen; import screens.TestIncorrectScreen; import screens.TestRightScreen; import util.Globals; import util.Util; import convergence.Convergence; import experiment.BasicJNDCondition; import experiment.Condition; import experiment.ExperimentControl; public class TestBasicJND extends JFrame implements KeyListener{ // TODO: add more states if needed // TODO: generalise this approach public static final int ORDER_BLOCKED = 1; public static final int ORDER_RANDOMIZED = 2; // Store conditions here // Note: not sure what the best data type to use is // though I do know that I might want to use // java.util.Collections.shuffle(List, Random) // at some point protected List myConditions = new Vector(); // Key mappings final int KEY_SPACE = KeyEvent.VK_SPACE; // avoid serialisation warnings private static final long serialVersionUID = 1L; public static final String LOG_FOLDER = ".\\logs\\"; private int trialNum = 1; // current trial number private int currentCondNum = 0; // current condition number private int capComplete = 30; // number of trials to cap conditions private int w, h; // Display height and width // Experiment state machine ExperimentControl expCtrl = new ExperimentControl(); // Screens Screen beginScreen = new BeginScreen(); Screen correctScreen = new TestCorrectScreen(); Screen incorrectScreen = new TestIncorrectScreen(); Screen currentStimuliScreen = new TestRightScreen(); Screen currentScreen; Image screenImage; // Data output file name private String dataFilename; // Conditions stuff private Condition currentCondition; private Vector conditions = new Vector(); // Place-holder private Convergence myConverge; // Constructor public TestBasicJND(Vector importedConditions){ this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // TODO: fix shallow copy conditions = importedConditions; currentCondition = (BasicJNDCondition)conditions.get(currentCondNum); // Set all conditions to end at a maximum of completeCap trials for(int i = 0; i<conditions.size(); i++)((BasicJNDCondition)conditions.get(i)).setTrialCompleteCap(capComplete); // Filename to output data to dataFilename = Util.getNow("yyyy-MM-dd_HHmmss"); dataFilename = dataFilename+".txt"; System.out.println(LogfileRow.getTitle()); try{ BufferedWriter out = new BufferedWriter(new FileWriter(LOG_FOLDER+dataFilename, false)); out.write(LogfileRow.getTitle() + "\n"); out.close(); }catch(IOException e){ e.printStackTrace(); System.exit(0); } currentScreen = beginScreen; screenImage = currentScreen.getImage(); setupListeners(); setupFullscreenWindow(); this.update(this.getGraphics()); } private void setupListeners(){ // Exit program on window close addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e) { System.exit(0); } }); addKeyListener(this); } private void setupFullscreenWindow(){ // set background color this.setBackground(Color.BLACK); // remove window frame this.setUndecorated(true); // window should be visible this.setVisible(true); // switch to fullscreen mode GraphicsEnvironment.getLocalGraphicsEnvironment(). getDefaultScreenDevice().setFullScreenWindow(this); w = this.getWidth(); h = this.getHeight(); if(Globals.isDebug){ System.out.println("Display: " + String.valueOf(w) + "x" + String.valueOf(h)); } } public void paint(Graphics g){ if (screenImage != null) g.drawImage(screenImage, w/2-screenImage.getWidth(this)/2, h/2-screenImage.getHeight(this)/2, this); } // From KeyListener public void keyPressed(KeyEvent arg0) { int correctKey = currentScreen.getCorrectKey(); int currentKey = arg0.getKeyCode(); // Exit program if ESC is pressed //if(currentKey == KeyEvent.VK_ESCAPE) System.exit(0); if(currentKey == KeyEvent.VK_ESCAPE){ this.getToolkit().getSystemEventQueue().postEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING)); } if(Globals.isDebug){ System.out.println("Current: " + currentKey); System.out.println("Correct: " + correctKey); } expCtrl.processInput(currentKey, currentScreen); switch(expCtrl.getCurrentState()){ case ExperimentControl.EXP_BEGIN: currentScreen = this.beginScreen; break; case ExperimentControl.EXP_FEEDBACK: // Append data to log file appendLogfileRow(Globals.GLOBAL_TIMER.toc(), correctKey, currentKey); // Set feedback screen and increment if(currentCondition.setTrialResponse(currentKey)){ currentScreen = this.correctScreen; }else{ currentScreen = this.incorrectScreen; } this.trialNum ++; // Handle completed conditions if(currentCondition.isCompleted()){ currentCondNum ++; if(currentCondNum >= conditions.size()){ expCtrl.setExpEnd(); currentScreen = new ExperimentEndScreen(); //doExperimentEnd(); // stupid hack, TODO: something smarter }else{ currentCondition = (BasicJNDCondition)(conditions.get(currentCondNum)); } } break; case ExperimentControl.EXP_END: doExperimentEnd(); break; case ExperimentControl.EXP_DISPLAY: currentScreen = currentCondition.getNextScreen(); Globals.GLOBAL_TIMER.tic(); break; } screenImage = currentScreen.getImage(); this.update(this.getGraphics()); } private void doExperimentEnd(){ System.out.println("Experiment Complete!"); System.exit(0); } private void appendLogfileRow(long trial_time_in_ms, int correctKey, int currentKey){ // very very dumb way to implement log file // LogfileRow(int trialNum, double trialTime, double base, double compare, double difference, boolean isCorrect, boolean isAscending, String side) // TODO: make the condition themselves print to the log file myConverge = currentCondition.getConvergence(); boolean isDescending = ((BasicJNDCondition)currentCondition).getIsDescending(); boolean isBaseOnLeft = ((BasicJNDCondition)currentCondition).getIsBaseOnLeft(); double scalingVal = ((BasicJNDCondition)currentCondition).getScalingVal(); int numPoint = ((BasicJNDCondition)currentCondition).getNumPoints(); double dotSize = ((BasicJNDCondition)currentCondition).getDotSize(); int dotStyle = ((BasicJNDCondition)currentCondition).getDotStyle(); int dotHue = ((BasicJNDCondition)currentCondition).getDotHue(); LogfileRow lr = new LogfileRow(trialNum, trial_time_in_ms, myConverge.getTrialParam(), myConverge.getTrialCompare(), Math.abs(myConverge.getTrialCompare()-myConverge.getTrialParam()), correctKey==currentKey, !isDescending, isBaseOnLeft?LogfileRow.RIGHT:LogfileRow.LEFT, scalingVal, dotSize, numPoint, dotStyle, dotHue); System.out.print(lr.toString() + "\n"); try{ BufferedWriter out = new BufferedWriter(new FileWriter(LOG_FOLDER+dataFilename, true)); out.write(lr.toString() + "\n"); out.close(); }catch(IOException e){ e.printStackTrace(); System.exit(0); } } public void keyReleased(KeyEvent arg0) { // TODO Auto-generated method stub } public void keyTyped(KeyEvent arg0) { // TODO Auto-generated method stub } // End KeyListener stuff /** * @param args */ public static void main(String[] args) { String condConfFile = ".\\conf\\TestBasicJND.cond"; Vector conditions = new Vector(); // public BasicJNDCondition(double base, double diff, boolean isConvAbove, int pointsLeft, int pointsRight, double errLeft, double errRight, double step) int pointsLeft = 500; int pointsRight = 500; double errLeft = 0.0001; double errRight = 0.0001; double step = 0.01; boolean isAxisOn = false; boolean isLabelsOn = false; try { FileInputStream fstream = new FileInputStream(condConfFile); // Get the object of DataInputStream DataInputStream in = new DataInputStream(fstream); BufferedReader br = new BufferedReader(new InputStreamReader(in)); String strLine; // Read File Line By Line while ((strLine = br.readLine()) != null) { System.out.println(strLine); // split via whitespace String tokens[] = strLine.split("\\s"); if(tokens.length >= 4){ if(tokens[0].equals("BasicJND")){ try{ double base = Double.parseDouble(tokens[1]); double diff = Double.parseDouble(tokens[2]); boolean isDescending = Boolean.parseBoolean(tokens[3]); int pointSize = 1; int pointStyle = 1; int dotHue = 1; System.out.println("Parsed: " + base + " " + diff + " " + isDescending); BasicJNDCondition tempCond = new BasicJNDCondition(base, diff, isDescending, pointsLeft, pointsRight, errLeft, errRight, step, isAxisOn, isLabelsOn, 1, pointSize, pointStyle, dotHue); conditions.add(tempCond); }catch(Exception e){ System.out.println("Parse error."); } } } } // Close the input stream in.close(); } catch (Exception e) {// Catch exception if any System.err.println("Error: " + e.getMessage()); } new TestBasicJND(conditions); } }