view ExperimentGui.java @ 47:be66ee2fe9fe

Added abstract class EndBlockPanel to deliver end of block messages (e.g. end of practice block). Added and implemented EndTestPanel which gives "thank you for participating" etc message at end of test.
author Carl Bussey <c.bussey@se10.qmul.ac.uk>
date Thu, 13 Jun 2013 18:33:34 +0100
parents 75354c638975
children 67ab1d1f9a87
line wrap: on
line source
/*=============================================================================
 * File:       ExperimentGui.java
 * Author:     Marcus Pearce <m.pearce@gold.ac.uk>
 * Created:    <2007-02-14 16:42:31 marcusp>
 * Time-stamp: <2011-11-04 17:41:45 marcusp>
 *=============================================================================
 */

import java.awt.*;
import javax.swing.*;
import java.util.ArrayList; 
import java.util.Iterator;

public class ExperimentGui extends JFrame implements Runnable {
    
    /* the Experiment */ 
    private Experiment exp; 

    /* The visual display indicating probe positions */ 
    private Clock clock; 

    /* The UI components */ 
    private JPanel mainPanel; 
    private InstructionsPanel instructionsPanel;
    private StimulusPanel stimulusPanel; 
    private SubjectDataPanel subjectDataPanel; 
    private InterBlockPanel interBlockPanel;
    private EndTestPanel endTestPanel;
    
    /* Whether we are accepting responses */ 
    private Boolean acceptingResponses; 
    
    /* accessors */ 
    public Boolean getAcceptingResponses() { return acceptingResponses; }
    public void setAcceptingResponses(Boolean b) { 
	if (b) 
	    debug("STARTED accepting responses");
	else
	    debug("STOPPED accepting responses");
        acceptingResponses = b;
	stimulusPanel.setResponseEnabled(b);
    }
    public Experiment getExperiment() { return exp; }
    public InstructionsPanel getInstructionsPanel() { return instructionsPanel; }
    public StimulusPanel getStimulusPanel() { return stimulusPanel; } 
    public SubjectDataPanel getSubjectDataPanel() { return subjectDataPanel; }
    public InterBlockPanel getInterBlockPanel() { return interBlockPanel; }
    public EndTestPanel getEndTestPanel() { return endTestPanel; }
    
    /* Constructor */ 
    public ExperimentGui(Experiment experiment) {

        
        
        // initialise experiment 
        exp = experiment; 
        acceptingResponses = false; 

        // set up the clock 
        clock = new Clock(exp.getDebug()); 
        
        // construct the frame
        JFrame.setDefaultLookAndFeelDecorated(true);
        this.getContentPane().setBackground (Color.black);
        this.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
        this.setLayout (new BorderLayout());
                
        // The different cards 
        instructionsPanel = new InstructionsPanel(this);
        stimulusPanel = new StimulusPanel(this, clock); 
        interBlockPanel = new InterBlockPanel(exp);
        endTestPanel = new EndTestPanel(exp);
        subjectDataPanel = new SubjectDataPanel(this, exp.getSubjectResults(), !exp.getAskFamiliarity());

	stimulusPanel.setResponseEnabled(false);
        
        // The Controller 
        ExperimentController ec = new ExperimentController(this); 

        // Show it all 
        CardLayout cl = new CardLayout(); 
        mainPanel = new JPanel(cl); 
        mainPanel.add(instructionsPanel, "instructions"); 
        mainPanel.add(interBlockPanel, "interblock");
        mainPanel.add(endTestPanel, "endTest");
        mainPanel.add(stimulusPanel, "stimulus"); 
        mainPanel.add(subjectDataPanel, "subject"); 

        this.add(mainPanel, BorderLayout.CENTER);
    }

    /* 
     * Methods for changing displayed card 
     */ 
    
    public void showCard(String card) { 
        CardLayout cl = (CardLayout)(mainPanel.getLayout());
        cl.show(mainPanel, card);
    }

    public void nextCard() { 
        CardLayout cl = (CardLayout)(mainPanel.getLayout());
        cl.next(mainPanel); 
    }
    
    /* Advance clock by 1 minute and redisplay. */
    public void tick(int n) {
        clock.tick(n);
        clock.repaint();
    }

    /* Show the Clock */ 
    public void showClock() { 
        if (exp.showClock()) {
            clock.showClock = true;
            clock.showFullClock = false; 
            clock.repaint();
        }
    } 

    /* Show the Fixation Point */ 
    public void showFixationPoint() { 
        debug("showFixationPoint");
        clock.showClock = false; 
        clock.showFullClock = false; 
        clock.repaint(); 
    } 
    
    /* Run clock for r revolutions at a rate of 1 minute (6 degrees)
     * every n milliseconds. 
     */
    public void runClock(int r, long n) {
        clock.reset(); 
        showClock(); 
        for (int i = 0; i < (60 * r); i++) {
            try { Thread.sleep (n); } catch (InterruptedException e) {}
               clock.tick(1);
               clock.repaint();
        }
        try { Thread.sleep (1000); } catch (InterruptedException e) {}
        showFixationPoint(); 
    }
    

    public void debug(String message) {
	if (exp.getDebug()) {
	    System.out.println(message);
	}
    }

    public void debugList(String name, ArrayList list) {
	if (exp.getDebug()) {
	    Iterator itr = list.iterator();
	    System.out.print("\n" + name + " (" + list.size() + "): ");
	    while (itr.hasNext()) {
		System.out.print(" " + itr.next());
	    }
	    System.out.print("\n");
	}
    }

    /* Run method for this thread */
    public void run() { 

	boolean debug = exp.getDebug();

	debug("\nBegin trial");
        //showFixationPoint(); 
        clock.reset(); 
        showClock(); 

        long tatum = exp.getCurrentBlock().getTatum(); 
        long tatumInMilliseconds = tatum / 1000; 
        int nMinutes = 60 / exp.getNumUnits(); 
        
	debug("Tatum: " + tatum);

        ArrayList onsets = exp.getCurrentBlock().getOnsets(); 
        ArrayList probes = exp.getCurrentBlock().getProbePositions(); 
        ArrayList clockStartTimes = exp.getCurrentBlock().getClockStartTimes(); 

	debugList("Onset times", onsets);
	debugList("Probe times", probes);
	debugList("Clock start times", clockStartTimes);
	
        Iterator oi = onsets.iterator(); 
        Iterator pi = probes.iterator(); 
        Iterator ci = clockStartTimes.iterator(); 
        
        ProbeID probe = ProbeID.NOT_PROBE; 

        long currentTime = 0; 
        long nextEventOnset = ((Long)(oi.next())).longValue();
        long nextClockStartTime = ((Long)(ci.next())).longValue();

        int clockUnit = 0; 
        boolean clockTicking = false; 

	do {// Using a do-while construct allows the user to enter a value at the end
	    // this should not really be in the 'view' anyway...
	    
	    debug("\n\nTicking = " + clockTicking + 
		  "; clockUnit = " + clockUnit + 
		  "; currentTime = " + currentTime + 
		  "; nextEventOnset = " + nextEventOnset + 
		  "; nextClockStartTime = " + nextClockStartTime);
	    
	    // Tick the clock every <clockUnit> cycles
	    if (clockTicking && clockUnit == 0) {
		debug("Tick");
		tick(nMinutes); 
	    }
            
	    // Start the clock
            if (currentTime >= nextClockStartTime) { 
		debug("Start clock (" + (currentTime - nextClockStartTime) + " ago)");
                //new Thread(clock).start(); 
                clock.reset(); 
                showClock(); 
                clockTicking = true; 
		
                if (ci.hasNext())
                    nextClockStartTime = ((Long)(ci.next())).longValue();
                else 
                    nextClockStartTime = Long.MAX_VALUE;
            }

	    // Event onset
            if (currentTime >= nextEventOnset) { 

                // Update probe identifier and onset 
		
		probe = (ProbeID) pi.next();
		debug("Event " + probe + " " + nextEventOnset + " (" + (currentTime - nextEventOnset) + " ago)");
		nextEventOnset = ((Long)(oi.next())).longValue();
		
                // Manipulate display depending on probe identifier
                switch (probe) { 
                case NOT_PROBE: 
		    // if (clock.showClock == true) 
                    //    tick(nMinutes); 
                    break; 
		    /* 
                case START_CLOCK:  // No longer used...
                    //clock.reset(); 
                    //showClock(); 
                    //tick(nMinutes); 
                    break; 
		    */
                case BEFORE_PROBE:
		    debug("BEFORE_PROBE: acceptingResponses = " + acceptingResponses); 
                    if (acceptingResponses) {
                        exp.getCurrentBlock().addResponse(0, System.nanoTime());
			debug("Recording zero response");
		    }
                    else 
                        setAcceptingResponses(true);
                    //tick(nMinutes); 
                    clockTicking = false; 
                    break; 
                case PROBE:
                case PROBE_EX:
                case PROBE_UNEX:
		    debug("PROBE_{UN,}EX: acceptingResponses = " + acceptingResponses); 
                    clock.showFullClock = false; 
                    clock.repaint(); 
                    break; 
                case AFTER_PROBE: 
                    showFixationPoint(); 
                    break; 
                default: 
                    System.out.println("Unexpected probe id: " + probe); 
                    break; 
                }
            } 

            // Sleep for tatum 
            try { Thread.sleep(tatumInMilliseconds); }
            catch (InterruptedException e) {}
            currentTime += tatum; 
            clockUnit = (clockUnit + 1) % exp.getClockUnits(); 

        } while(oi.hasNext());

        showFixationPoint(); 
    }



}