// --------------------------------------- // Restricted Focus Viewer (RFV) Program // Version 2.1 // Language: Java 2 // November, 2000 // Copyright (C) 2000 Anthony R. Jansen // --------------------------------------- // 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. // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // --------------------------------------- // Replayer.java // // This is the core class for the Replayer // program which accompanies the RFV. It // allows the contents of the RFV data // files to be replayed, at various // speeds, and in various modes. // --------------------------------------- // --------------------------------------- // Modified May, 2001 // by Anthony R. Jansen // // Modified to allow the selection window // to remain always visible so that a // different block can be selected at any // time without having to rerun the // program. // --------------------------------------- import java.io.*; import java.awt.*; import java.awt.event.*; import java.util.LinkedList; public class Replayer implements KeyListener, ActionListener { // Variables for Replayer status // ----------------------------- private boolean running; private boolean paused; private boolean guide_box; private int current_data_point; private int speed_factor; // Arrays to store the RFV data // ---------------------------- private Replayer_Stimulus_Data data[]; private int num_data_points; // Required components // ------------------- private RFV_Defaults defaults; private Replayer_Selection_Window selection_window; private RFV_Display_Window display_window; private RFV_Timer replayer_timer; private Replayer_Thread replayer_thread; private Replayer_Status_Image status_image; // I/O file handling variables // --------------------------- private RFV_Input_File input_file; private LinkedList component_list; // Constants // --------- private static final String TITLE = "Replayer Version 2.1"; public static final int QUARTER_SPEED = 1; public static final int HALF_SPEED = 2; public static final int NORMAL_SPEED = 3; public static final int DOUBLE_SPEED = 4; public static final int QUADRUPLE_SPEED = 5; private static final int STATUS_WIDTH = 95; private static final int STATUS_HEIGHT = 30; // Constructor which accepts the data filename // as its argument and displays the selection window // ------------------------------------------------- public Replayer(String data_filename) { display_window = null; selection_window = new Replayer_Selection_Window(this, data_filename); } // Deal with run button press on selection window // If settings are valid, create display window // ---------------------------------------------- public void actionPerformed(ActionEvent ae) { String component; String block; String input_filename; // Check settings are valid // ------------------------ if (selection_window == null || !selection_window.isValidSettings()) return; // Get settings // ------------ data = selection_window.getDataPoints(); num_data_points = data.length; input_filename = selection_window.getInputFilename(); component = selection_window.getComponent(); block = selection_window.getBlock(); // Open the input file and read in the components // and then get rid of the selection window // ---------------------------------------------- input_file = new RFV_Input_File(input_filename); readDefaultsAndComponents(); // Do not remove selection window // ------------------------------ // selection_window.hide(); // selection_window.dispose(); // selection_window = null; // If there is an old display window, destroy it // --------------------------------------------- if (display_window != null) { running = false; if (replayer_thread != null) replayer_thread.interrupt(); display_window.hide(); display_window.dispose(); display_window = null; } // Initialize variables // -------------------- running = false; paused = false; guide_box = false; current_data_point = 0; speed_factor = NORMAL_SPEED; replayer_timer = null; replayer_timer = new RFV_Timer(); replayer_thread = null; // Create display window and add listeners for interaction // ------------------------------------------------------- display_window = new RFV_Display_Window(defaults, true); status_image = new Replayer_Status_Image( display_window.createImage(Replayer_Status_Image.STATUS_WIDTH, Replayer_Status_Image.STATUS_HEIGHT), defaults); display_window.setReplayerStatusImage(status_image); loadBlock(component, getBlockNumber(block)); display_window.addKeyListener(this); updateReplayerBaseImage(); } // Works out the block number from a string // ---------------------------------------- private int getBlockNumber(String string) { int number = 0; try { string = string.substring(5).trim(); if (string.charAt(string.length()-1) == '*') string = string.substring(0, string.length()-1).trim(); number = Integer.parseInt(string); } catch(IndexOutOfBoundsException e1) { RFV_Error.die(73); } catch(NumberFormatException e2) { RFV_Error.die(74); } return number; } // Reads in the components // ----------------------- private void readDefaultsAndComponents() { String token; // Expect defaults parameter first // ------------------------------- token = input_file.readToken(); if (!token.equalsIgnoreCase("defaults")) RFV_Error.die(1, input_file.getLineNumber()); defaults = new RFV_Defaults(input_file, selection_window.getGraphics()); // Read in the component labels // ---------------------------- component_list = new LinkedList(); token = input_file.readToken(); while (!token.equals(RFV_Input_File.EOF)) { if (!token.equalsIgnoreCase("component")) RFV_Error.die(2, input_file.getLineNumber()); input_file.readOpenBracket(); token = input_file.readLabel(); component_list.add(input_file.getFileIndex(token)); input_file.matchOpenBrackets(1); token = input_file.readToken(); } // Check that there are components // ------------------------------- if (component_list.size() == 0) RFV_Error.die(3); } // Loads the appropriate block // --------------------------- private void loadBlock(String component, int block_number) { RFV_File_Index index = null; String token; boolean flag = false; try { for (int i = 0; i < component_list.size(); i++) { index = (RFV_File_Index) component_list.get(i); if ((index.label).equals(component)) { flag = true; break; } } if (!flag) RFV_Error.die(75); input_file.setFileIndex(index); } catch(IndexOutOfBoundsException e) { RFV_Error.die(5); } // Pass other blocks // ----------------- while (block_number > 1) { token = input_file.readToken(); input_file.readOpenBracket(); input_file.matchOpenBrackets(1); block_number--; } // Read in block parameter // ----------------------- token = input_file.readToken(); if (!token.equalsIgnoreCase("block")) RFV_Error.die(6, input_file.getLineNumber(), token); display_window.readBlock(input_file); display_window.resetReplayerImages(); } // Updates the replayer base image // ------------------------------- public synchronized void updateReplayerBaseImage() { LinkedList stimulus_list; RFV_Stimulus stimulus; // Check that display window still exits // ------------------------------------- if (display_window == null) return; Graphics g1 = display_window.getBlurredGraphics(); Graphics g2 = display_window.getFocusGraphics(); Graphics dw = display_window.getGraphics(); if (current_data_point == 0) { display_window.resetReplayerImages(); display_window.paint(dw); } else if (current_data_point < num_data_points) { stimulus_list = display_window.getBlock().getStimulusList(); try { if (data[current_data_point-1].stimulus != 0 && data[current_data_point-1].stimulus != data[current_data_point].stimulus) { stimulus = (RFV_Stimulus) stimulus_list. get(data[current_data_point-1].stimulus-1); stimulus.mouseOff(); stimulus.draw(g1); if (display_window.getReplayerMode() == RFV_Display_Window.FOCUS_WINDOW_MODE) stimulus.draw(dw); } if (data[current_data_point].stimulus != 0) { stimulus = (RFV_Stimulus) stimulus_list. get(data[current_data_point].stimulus-1); stimulus.mouseOn(data[current_data_point].x_pos, data[current_data_point].y_pos, data[current_data_point].motion_blur); stimulus.draw(g1); if (display_window.getReplayerMode() == RFV_Display_Window.FOCUS_WINDOW_MODE) stimulus.draw(dw); } } catch(IndexOutOfBoundsException e) { RFV_Error.die(76); } g2.setColor(Color.red); g2.drawLine(data[current_data_point].x_pos, data[current_data_point].y_pos, data[current_data_point-1].x_pos, data[current_data_point-1].y_pos); if (display_window.getReplayerMode() == RFV_Display_Window.SCAN_PATH_MODE) { dw.setColor(Color.red); dw.drawLine(data[current_data_point].x_pos, data[current_data_point].y_pos, data[current_data_point-1].x_pos, data[current_data_point-1].y_pos); } } } // Execute commands for particular key presses // ------------------------------------------- public synchronized void keyTyped(KeyEvent ke) { // If it comes from the selection window // ------------------------------------- if (ke.getComponent() != display_window) { // If Q is pressed, then exit // -------------------------- if (ke.getKeyChar() == 'q' || ke.getKeyChar() == 'Q') System.exit(0); return; } Graphics dw = display_window.getGraphics(); long elapsed_time = 0; // If Q is pressed, destroy display window // --------------------------------------- if (ke.getKeyChar() == 'q' || ke.getKeyChar() == 'Q') { running = false; if (replayer_thread != null) replayer_thread.interrupt(); display_window.hide(); display_window.dispose(); display_window = null; } // If R is pressed, then reset // --------------------------- else if (ke.getKeyChar() == 'r' || ke.getKeyChar() == 'R') { if (running) { running = false; if (replayer_thread != null) replayer_thread.interrupt(); paused = false; status_image.update(running, paused, speed_factor); } current_data_point = 0; updateReplayerBaseImage(); } // If M is pressed, change mode // ---------------------------- else if (ke.getKeyChar() == 'm' || ke.getKeyChar() == 'M') { display_window.changeMode(); display_window.paint(dw); } // If T is press, toggle status region on/off // ------------------------------------------ else if (ke.getKeyChar() == 't' || ke.getKeyChar() == 'T') { status_image.toggleVisible(); display_window.paint(dw); } // If S is pressed and not already running, start replay // ----------------------------------------------------- else if (ke.getKeyChar() == 's' || ke.getKeyChar() == 'S') { if (!running) { current_data_point = 0; paused = false; replayer_timer.reset(); replayer_thread = new Replayer_Thread(this); if (replayer_thread == null) RFV_Error.die(77); replayer_thread.setPriority(Thread.MIN_PRIORITY); replayer_thread.start(); running = true; status_image.update(running, paused, speed_factor); updateReplayerBaseImage(); } } // If P is pressed, toggle pause // ----------------------------- else if (ke.getKeyChar() == 'p' || ke.getKeyChar() == 'P') { if (!paused && running) { replayer_timer.pause(); paused = true; advanceOneDataPoint(); status_image.update(running, paused, speed_factor); status_image.draw(dw); } else if (paused && running) { replayer_timer.unpause(); paused = false; status_image.update(running, paused, speed_factor); status_image.draw(dw); } } // If G is pressed, toggle guide box // --------------------------------- else if (ke.getKeyChar() == 'g' || ke.getKeyChar() == 'G') { LinkedList stimulus_list; RFV_Stimulus stimulus; if (guide_box) guide_box = false; else guide_box = true; stimulus_list = display_window.getBlock().getStimulusList(); try { for (int i = 0; i < stimulus_list.size(); i++) { stimulus = (RFV_Stimulus) stimulus_list.get(i); stimulus.setGuideBox(guide_box); } } catch(IndexOutOfBoundsException e) { RFV_Error.die(78); } } // If > is pressed, increase speed if paused or not running // -------------------------------------------------------- else if (ke.getKeyChar() == '>' || ke.getKeyChar() == '.') { if (speed_factor < QUADRUPLE_SPEED) { speed_factor++; elapsed_time = replayer_timer.getElapsed(); replayer_timer.setElapsed(elapsed_time / 2); status_image.update(running, paused, speed_factor); status_image.draw(dw); } } // If < is pressed, decrease speed if paused or not running // -------------------------------------------------------- else if (ke.getKeyChar() == '<' || ke.getKeyChar() == ',') { if (speed_factor > QUARTER_SPEED) { speed_factor--; elapsed_time = replayer_timer.getElapsed(); replayer_timer.setElapsed(elapsed_time * 2); status_image.update(running, paused, speed_factor); status_image.draw(dw); } } // If F is pressed and pause is true, advance one data point // --------------------------------------------------------- else if (ke.getKeyChar() == 'f' || ke.getKeyChar() == 'F') advanceOneDataPoint(); } // Ends a replay // ------------- public synchronized void endReplay() { if (running) { running = false; status_image.update(running, paused, speed_factor); status_image.draw(display_window.getGraphics()); } replayer_thread = null; } // Increments the current data point // --------------------------------- public void incrementCurrentDataPoint() { current_data_point++; } // Returns the time of current data point // -------------------------------------- public int getCurrentDataPointTime() { return data[current_data_point].time; } // Returns the elapsed replay time // ------------------------------- public int getElapsedReplayTime() { return (int) replayer_timer.getElapsed(); } // Returns the current data point // ------------------------------ public int getCurrentDataPoint() { return current_data_point; } // Returns the speed factor // ------------------------ public int getSpeedFactor() { return speed_factor; } // Returns the number of data points // --------------------------------- public int getNumDataPoints() { return num_data_points; } // Method to advance the paused replay by one data point // ----------------------------------------------------- private synchronized void advanceOneDataPoint() { long elapsed_time = 0; if (running && paused) { if (speed_factor == QUARTER_SPEED) elapsed_time = data[current_data_point].time * 4; else if (speed_factor == HALF_SPEED) elapsed_time = data[current_data_point].time * 2; else if (speed_factor == NORMAL_SPEED) elapsed_time = data[current_data_point].time; else if (speed_factor == DOUBLE_SPEED) elapsed_time = data[current_data_point].time / 2; else if (speed_factor == QUADRUPLE_SPEED) elapsed_time = data[current_data_point].time / 4; replayer_timer.setElapsed(elapsed_time); } } // Extra methods from the KeyListener interface that were not used // --------------------------------------------------------------- public void keyPressed(KeyEvent ke) { ; } public void keyReleased(KeyEvent ke) { ; } // Main method to start the program, accepting // the data filename as an argument // ------------------------------------------- static public void main(String argv[]) { if (argv.length != 1) { System.out.println(" "); System.out.println("Restricted Focus Viewer (RFV) Replayer, " + "Version 2.1"); System.out.println(" "); System.out.println("Copyright (C) 2000 Anthony R. Jansen"); System.out.println(" "); System.out.println("This program may only be copied under the " + "terms of the GNU General Public"); System.out.println("License, which may be found along with " + "the program documentation on the"); System.out.println("RFV website at " + "http://www.csse.monash.edu.au/~tonyj/RFV/"); System.out.println(" "); System.exit(0); } Replayer replayer = new Replayer(argv[0]); } }