package toy.dialog; import java.awt.*; import java.awt.event.*; import java.io.*; import toy.*; import toy.image.*; /** * * @author Brian Tsang * @version 7.0 */ public class ToyPopup extends Dialog implements ActionListener, ItemListener, Runnable { //////////////////////////////////////////////////////////////////////////// // Constants public static final int LABEL_WIDTH = 400; public static final int MAX_PREVIEW_LINES = 7; public static final Font SANSSERIF = new Font("SansSerif", Font.PLAIN, 12); public static final Font MONOSPACED = new Font("Monospaced", Font.PLAIN, 12); //////////////////////////////////////////////////////////////////////////// // Variables private boolean response; //this is the response the user gave (true = ok, false = cancel) private String exampleTitles[], examplePrograms[]; private ToyRefreshablePanel refreshablePanel; private ToyVirtualMachine virtualMachine; private Thread runner; private boolean uninitializedErrorEnabled, overflowErrorEnabled, outOfBoundsErrorEnabled; private CheckboxMenuItem closeExecutionCheckbox; private List exampleTitleList; private Label exampleProgramLabels[]; private Label executingLabel; private Label elapsedTimeLabel; private Label stepsExecutedLabel; private Checkbox closeOnHaltCheckbox; private ToyAnimatedIcon animatedIcon; private TextArea inputTextArea; private Button trueButton, falseButton; //////////////////////////////////////////////////////////////////////////// // The constructors private ToyPopup(Frame parent) { super(parent, "Toy Dialog", true); setResizable(false); enableEvents(AWTEvent.WINDOW_EVENT_MASK); } private ToyPopup(Dialog parent) { super(parent, "Toy Dialog", true); setResizable(false); enableEvents(AWTEvent.WINDOW_EVENT_MASK); } //////////////////////////////////////////////////////////////////////////// // override the pack() function to also center the dialog public void pack() { super.pack(); Rectangle currentBounds = getBounds(); Rectangle parentBounds = getParent().getBounds(); setBounds( parentBounds.x + (parentBounds.width - currentBounds.width) / 2, parentBounds.y + (parentBounds.height - currentBounds.height) / 2, currentBounds.width, currentBounds.height ); } //////////////////////////////////////////////////////////////////////////// // newPopup() is a special pseudo-constructor which will take a component, // find it's parent frame, and return a new ToyPopup as a child to that // frame (I couldn't make this a constructor because of some tough rules on // when you can use super()) private static ToyPopup newPopup(Component windowChild) { Container currentContainer; if (windowChild instanceof Container) currentContainer = (Container)windowChild; else currentContainer = windowChild.getParent(); while (currentContainer != null && !(currentContainer instanceof Frame) && !(currentContainer instanceof Dialog && ToyToolkit.dialogParentCanBeDialog())) currentContainer = currentContainer.getParent(); if (currentContainer == null) return null; if (currentContainer instanceof Frame) return new ToyPopup((Frame)currentContainer); else return new ToyPopup((Dialog)currentContainer); } //////////////////////////////////////////////////////////////////////////// // askUser() is a (static/non-static) function which (creates/uses this // instance) to ask the user a question with one or two possible reponses public static void askUser(Component windowChild, String dialogTitle, String dialogText, String trueButtonText) { try { newPopup(windowChild).askUser( dialogTitle, dialogText, trueButtonText, null ); } catch (Exception e) { e.printStackTrace(); } } public static boolean askUser(Component windowChild, String dialogTitle, String dialogText, String trueButtonText, String falseButtonText) { try { return newPopup(windowChild).askUser( dialogTitle, dialogText, trueButtonText, falseButtonText ); } catch (Exception e) { e.printStackTrace(); return true; } } private boolean askUser(String dialogTitle, String dialogText, String trueButtonText, String falseButtonText) { if (isShowing()) throw new RuntimeException("ToyPopup instance used twice simultaneously"); setTitle(dialogTitle); String wrappedString[] = ToyToolkit.wordWrap( dialogText, SANSSERIF, LABEL_WIDTH ); //begin laying out the components setForeground(new Color (0, 0, 0)); setBackground(new Color(192, 192, 192)); setLayout(new GridBagLayout()); Panel contentPanel = new Panel(new GridBagLayout()); add( contentPanel, ToyToolkit.createGridBagConstraints( 0, 0, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(10, 10, 10, 10), 0, 0 ) ); //make as many text labels as necessary for (int ctr = 0; ctr < wrappedString.length; ctr++) { Label textLabel = new Label(wrappedString[ctr]); textLabel.setFont(SANSSERIF); contentPanel.add( textLabel, ToyToolkit.createGridBagConstraints( 0, ctr, 1, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0 ) ); } //ensure that the labels are at least LABEL_WIDTH long contentPanel.add( new ToySpacer(LABEL_WIDTH, 0), ToyToolkit.createGridBagConstraints( 0, wrappedString.length, 1, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0 ) ); //does the user want a false button? if (falseButtonText == null) { //if not, then center the true button Panel buttonPanel = new Panel(new GridLayout(2, 1, 0, 0)); contentPanel.add( buttonPanel, ToyToolkit.createGridBagConstraints( 0, wrappedString.length + 1, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0 ) ); buttonPanel.add(new ToySpacer(80, 0)); trueButton = new Button(trueButtonText); trueButton.setActionCommand("true"); trueButton.setFont(SANSSERIF); trueButton.addActionListener(this); buttonPanel.add(trueButton); } else { //otherwise align the true and false buttons to the right Panel buttonPanel = new Panel(new GridLayout(2, 2, 10, 0)); contentPanel.add( buttonPanel, ToyToolkit.createGridBagConstraints( 0, wrappedString.length + 1, 1, 1, 1.0, 1.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0 ) ); buttonPanel.add(new ToySpacer(80, 0)); buttonPanel.add(new ToySpacer(80, 0)); trueButton = new Button(trueButtonText); trueButton.setActionCommand("true"); trueButton.setFont(SANSSERIF); trueButton.addActionListener(this); buttonPanel.add(trueButton); falseButton = new Button(falseButtonText); falseButton.setActionCommand("false"); falseButton.setFont(SANSSERIF); falseButton.addActionListener(this); buttonPanel.add(falseButton); } pack(); show(); return response; } //////////////////////////////////////////////////////////////////////////// // askForInput() is a (static/non-static) function which (creates/uses this // instance) to ask the user for input, if specified, this dialog will // also accept an Abort command public static void askForInput(Component windowChild, ToyVirtualMachine newVirtualMachine) { try { newPopup(windowChild).askForInput(newVirtualMachine, false); } catch (Exception e) { e.printStackTrace(); } } public static boolean askForInput(Component windowChild, ToyVirtualMachine newVirtualMachine, boolean allowAbort) { try { return newPopup(windowChild).askForInput(newVirtualMachine, allowAbort); } catch (Exception e) { e.printStackTrace(); return false; } } private boolean askForInput(ToyVirtualMachine newVirtualMachine, boolean allowAbort) { if (isShowing()) throw new RuntimeException("ToyPopup instance used twice simultaneously"); virtualMachine = newVirtualMachine; setTitle("Input Request"); String wrappedString[]; if (allowAbort) { wrappedString = ToyToolkit.wordWrap( "The Stdin buffer is empty.\n" + "\n" + "\tPlease input more data into the input buffer and " + "push the \"Done\" button to continue the execution or " + "push the \"Abort\" button to terminate the execution.", SANSSERIF, LABEL_WIDTH ); } else { wrappedString = ToyToolkit.wordWrap( "The Stdin buffer is empty.\n" + "\n" + "\tPlease input more data into the input buffer and " + "push the \"Done\" button. If you wish to abort, just press" + "the \"Done\" button; this prompt will not appear until the " + "next time you attempt to execute a read() command on an " + "empty stdin buffer.", SANSSERIF, LABEL_WIDTH ); } //begin laying out the components setForeground(new Color (0, 0, 0)); setBackground(new Color(192, 192, 192)); setLayout(new GridBagLayout()); Panel contentPanel = new Panel(new GridBagLayout()); add( contentPanel, ToyToolkit.createGridBagConstraints( 0, 0, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(10, 10, 10, 10), 0, 0 ) ); //make as many text labels as necessary for (int ctr = 0; ctr < wrappedString.length; ctr++) { Label textLabel = new Label(wrappedString[ctr]); textLabel.setFont(SANSSERIF); contentPanel.add( textLabel, ToyToolkit.createGridBagConstraints( 0, ctr, 1, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0 ) ); } //add the input panel ToyInputPanel inputPanel = new ToyInputPanel(new ToyFocusManager()); inputPanel.setVirtualMachine(virtualMachine); contentPanel.add( inputPanel, ToyToolkit.createGridBagConstraints( 0, wrappedString.length, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0 ) ); //ensure that the labels are at least LABEL_WIDTH long contentPanel.add( new ToySpacer(LABEL_WIDTH, 0), ToyToolkit.createGridBagConstraints( 0, wrappedString.length + 1, 1, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0 ) ); //does the user want a false button? if (!allowAbort) { //if not, then center the true button Panel buttonPanel = new Panel(new GridLayout(2, 1, 0, 0)); contentPanel.add( buttonPanel, ToyToolkit.createGridBagConstraints( 0, wrappedString.length + 2, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0 ) ); buttonPanel.add(new ToySpacer(80, 0)); trueButton = new Button("Done"); trueButton.setActionCommand("true"); trueButton.setFont(SANSSERIF); trueButton.addActionListener(this); buttonPanel.add(trueButton); } else { //otherwise align the true and false buttons to the right Panel buttonPanel = new Panel(new GridLayout(2, 2, 10, 0)); contentPanel.add( buttonPanel, ToyToolkit.createGridBagConstraints( 0, wrappedString.length + 2, 1, 1, 1.0, 1.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0 ) ); buttonPanel.add(new ToySpacer(80, 0)); buttonPanel.add(new ToySpacer(80, 0)); trueButton = new Button("Done"); trueButton.setActionCommand("true"); trueButton.setFont(SANSSERIF); trueButton.addActionListener(this); buttonPanel.add(trueButton); falseButton = new Button("Abort"); falseButton.setActionCommand("false"); falseButton.setFont(SANSSERIF); falseButton.addActionListener(this); buttonPanel.add(falseButton); } pack(); getParent().repaint(); show(); return response; } //////////////////////////////////////////////////////////////////////////// // editInput() is a (static/non-static) function which (creates/uses this // instance) to ask the user for input public static void editInput(Component windowChild, ToyVirtualMachine newVirtualMachine) { try { newPopup(windowChild).editInput(newVirtualMachine); } catch (Exception e) { e.printStackTrace(); } } private void editInput(ToyVirtualMachine newVirtualMachine) { if (isShowing()) throw new RuntimeException("ToyPopup instance used twice simultaneously"); setTitle("Edit Input"); //begin laying out the components setForeground(new Color (0, 0, 0)); setBackground(new Color(192, 192, 192)); setLayout(new GridBagLayout()); Panel contentPanel = new Panel(new GridBagLayout()); add( contentPanel, ToyToolkit.createGridBagConstraints( 0, 0, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(10, 10, 10, 10), 0, 0 ) ); ToyWord stdin[] = newVirtualMachine.getStdin(); String textAreaString = ""; for (int ctr = 0; ctr < stdin.length; ctr++) textAreaString += stdin[ctr].toHexString() + "\n"; //make the Input text area inputTextArea = new TextArea(textAreaString, 10, 8); inputTextArea.setFont(MONOSPACED); contentPanel.add( inputTextArea, ToyToolkit.createGridBagConstraints( 0, 0, 1, 5, 3.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 10), 0, 0 ) ); //make a open button Button openButton = new Button("Open..."); openButton.setActionCommand("open"); openButton.setEnabled(ToyToolkit.hasFilePermissions()); openButton.setFont(SANSSERIF); openButton.addActionListener(this); contentPanel.add( openButton, ToyToolkit.createGridBagConstraints( 1, 0, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 10, 0), 0, 0 ) ); //make a save button Button saveButton = new Button("Save As..."); saveButton.setActionCommand("save"); saveButton.setEnabled(ToyToolkit.hasFilePermissions()); saveButton.setFont(SANSSERIF); saveButton.addActionListener(this); contentPanel.add( saveButton, ToyToolkit.createGridBagConstraints( 1, 1, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0 ) ); //make a spacer contentPanel.add( new ToySpacer(80, 0), ToyToolkit.createGridBagConstraints( 1, 2, 1, 1, 1.0, 100.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0 ) ); //make a true button trueButton = new Button("OK"); trueButton.setActionCommand("true"); trueButton.setFont(SANSSERIF); trueButton.addActionListener(this); contentPanel.add( trueButton, ToyToolkit.createGridBagConstraints( 1, 3, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 10, 0), 0, 0 ) ); //make a false button falseButton = new Button("Cancel"); falseButton.setActionCommand("false"); falseButton.setFont(SANSSERIF); falseButton.addActionListener(this); contentPanel.add( falseButton, ToyToolkit.createGridBagConstraints( 1, 4, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0 ) ); //add another spacer contentPanel.add( new ToySpacer(LABEL_WIDTH, 0), ToyToolkit.createGridBagConstraints( 0, 5, 2, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0 ) ); pack(); show(); if (response) { //change stdin based on the contents of the Text Area textAreaString = inputTextArea.getText(); stdin = new ToyWord[0]; int beginCtr = 0, endCtr = 0; while (endCtr < textAreaString.length()) { beginCtr = endCtr; //advance beginCtr to the next hex digit while (beginCtr < textAreaString.length() && !ToyWord.isHexDigit(textAreaString.charAt(beginCtr))) beginCtr++; //advance endCtr to the next non-hex digit or 4 characters, //whichever is less endCtr = beginCtr + 1; while (endCtr < textAreaString.length() && endCtr < beginCtr + 4 && ToyWord.isHexDigit(textAreaString.charAt(endCtr))) endCtr++; if (beginCtr < textAreaString.length()) { char charArray[] = new char[4]; ToyWord oldStdin[] = stdin; stdin = new ToyWord[oldStdin.length + 1]; for (int ctr = 0; ctr < oldStdin.length; ctr++) stdin[ctr] = oldStdin[ctr]; for (int ctr = 0; ctr < 4; ctr++) { if (endCtr - 4 + ctr < beginCtr) charArray[ctr] = '0'; else charArray[ctr] = textAreaString.charAt(endCtr - 4 + ctr); } stdin[oldStdin.length] = ToyWord.parseHexidecimal( charArray[0], charArray[1], charArray[2], charArray[3] ); } } newVirtualMachine.setStdin(stdin); } } //////////////////////////////////////////////////////////////////////////// // getExampleChoice() is a (static/non-static) function which (creates/uses // this instance) to get an example that the user wants to view public static int getExampleChoice(Component windowChild, String newExampleTitle[], String newExampleProgram[]) { try { return newPopup(windowChild).getExampleChoice( newExampleTitle, newExampleProgram ); } catch (Exception e) { e.printStackTrace(); return -1; } } private int getExampleChoice(String newExampleTitle[], String newExampleProgram[]) { if (isShowing()) throw new RuntimeException("ToyPopup instance used twice simultaneously"); exampleTitles = newExampleTitle; examplePrograms = newExampleProgram; setTitle("Open Example Program"); //begin laying out the components setForeground(new Color (0, 0, 0)); setBackground(new Color(192, 192, 192)); setLayout(new GridBagLayout()); Panel contentPanel = new Panel(new GridBagLayout()); add( contentPanel, ToyToolkit.createGridBagConstraints( 0, 0, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(10, 10, 10, 10), 0, 0 ) ); exampleTitleList = new List(6); exampleTitleList.addItemListener(this); exampleTitleList.setFont(SANSSERIF); for (int ctr = 0; ctr < exampleTitles.length; ctr++) exampleTitleList.add(exampleTitles[ctr]); contentPanel.add( exampleTitleList, ToyToolkit.createGridBagConstraints( 0, 0, 1, 1, 1.0, 30.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0 ) ); //make as many text labels as necessary exampleProgramLabels = new Label[MAX_PREVIEW_LINES]; for (int ctr = 0; ctr < MAX_PREVIEW_LINES; ctr++) { exampleProgramLabels[ctr] = new Label(); exampleProgramLabels[ctr].setFont(MONOSPACED); contentPanel.add( exampleProgramLabels[ctr], ToyToolkit.createGridBagConstraints( 0, ctr + 1, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0 ) ); } //ensure that the labels are at least 80 characters long contentPanel.add( new ToySpacer( ToyToolkit.getFontMetrics(MONOSPACED).stringWidth( ToyWorkspace.HEADER_BAR + "**" ), 0 ), ToyToolkit.createGridBagConstraints( 0, MAX_PREVIEW_LINES + 1, 1, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0 ) ); //align the true and false buttons to the right Panel buttonPanel = new Panel(new GridLayout(2, 2, 10, 0)); contentPanel.add( buttonPanel, ToyToolkit.createGridBagConstraints( 0, MAX_PREVIEW_LINES + 2, 1, 1, 1.0, 1.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0 ) ); buttonPanel.add(new ToySpacer(80, 0)); buttonPanel.add(new ToySpacer(80, 0)); trueButton = new Button("OK"); trueButton.setActionCommand("true"); trueButton.setFont(SANSSERIF); trueButton.addActionListener(this); buttonPanel.add(trueButton); falseButton = new Button("Cancel"); falseButton.setActionCommand("false"); falseButton.setFont(SANSSERIF); falseButton.addActionListener(this); buttonPanel.add(falseButton); pack(); show(); int answer; if (response) answer = exampleTitleList.getSelectedIndex(); else answer = -1; return answer; } //////////////////////////////////////////////////////////////////////////// // execute() is a (static/non-static) function which (creates/uses this // instance) to execute the toy program public static void execute(Component windowChild, ToyRefreshablePanel newRefreshablePanel, ToyImageManager newImageManager, ToyVirtualMachine newVirtualMachine, CheckboxMenuItem newCloseExecutionCheckbox ) { try { newPopup(windowChild).execute( newRefreshablePanel, newImageManager, newVirtualMachine, false, false, false, newCloseExecutionCheckbox ); } catch (Exception e) { e.printStackTrace(); } } public static void execute(Component windowChild, ToyRefreshablePanel newRefreshablePanel, ToyImageManager newImageManager, ToyVirtualMachine newVirtualMachine, boolean newUninitializedErrorEnabled, boolean newOverflowErrorEnabled, boolean newOutOfBoundsErrorEnabled, CheckboxMenuItem newCloseExecutionCheckbox ) { try { newPopup(newRefreshablePanel).execute( newRefreshablePanel, newImageManager, newVirtualMachine, newUninitializedErrorEnabled, newOverflowErrorEnabled, newOutOfBoundsErrorEnabled, newCloseExecutionCheckbox ); } catch (Exception e) { e.printStackTrace(); } } public void execute(ToyRefreshablePanel newRefreshablePanel, ToyImageManager newImageManager, ToyVirtualMachine newVirtualMachine, CheckboxMenuItem newCloseExecutionCheckbox ) { if (isShowing()) throw new RuntimeException( "ToyExecutionPopup instance used twice simultaneously" ); execute( newRefreshablePanel, newImageManager, newVirtualMachine, false, false, false, newCloseExecutionCheckbox ); } private void execute(ToyRefreshablePanel newRefreshablePanel, ToyImageManager newImageManager, ToyVirtualMachine newVirtualMachine, boolean newUninitializedErrorEnabled, boolean newOverflowErrorEnabled, boolean newOutOfBoundsErrorEnabled, CheckboxMenuItem newCloseExecutionCheckbox ) { if (isShowing()) throw new RuntimeException( "ToyExecutionPopup instance used twice simultaneously" ); refreshablePanel = newRefreshablePanel; virtualMachine = newVirtualMachine; uninitializedErrorEnabled = newUninitializedErrorEnabled; overflowErrorEnabled = newOverflowErrorEnabled; outOfBoundsErrorEnabled = newOutOfBoundsErrorEnabled; closeExecutionCheckbox = newCloseExecutionCheckbox; setTitle("Executing Toy Program"); //begin laying out the components setForeground(new Color (0, 0, 0)); setBackground(new Color(192, 192, 192)); setLayout(new GridBagLayout()); Panel contentPanel = new Panel(new GridBagLayout()); add( contentPanel, ToyToolkit.createGridBagConstraints( 0, 0, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(10, 10, 10, 10), 0, 0 ) ); executingLabel = new Label("Executing X-TOY Program..."); executingLabel.setFont(SANSSERIF); contentPanel.add( executingLabel, ToyToolkit.createGridBagConstraints( 0, 0, 1, 1, 100.0, 1.0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 10), 0, 0 ) ); elapsedTimeLabel = new Label(" Elapsed Time: 0.000 s"); elapsedTimeLabel.setFont(SANSSERIF); contentPanel.add( elapsedTimeLabel, ToyToolkit.createGridBagConstraints( 0, 1, 1, 1, 100.0, 1.0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 10), 0, 0 ) ); //make as many text labels as necessary stepsExecutedLabel = new Label(" Steps Executed: 0"); stepsExecutedLabel.setFont(SANSSERIF); contentPanel.add( stepsExecutedLabel, ToyToolkit.createGridBagConstraints( 0, 2, 1, 1, 100.0, 1.0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 10), 0, 0 ) ); //put as much space between the labels and the checkbox as necessary contentPanel.add( new ToySpacer(0, 0), ToyToolkit.createGridBagConstraints( 0, 3, 1, 1, 100.0, 100.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 10), 0, 0 ) ); closeOnHaltCheckbox = new Checkbox( "Close this window when the program halts", closeExecutionCheckbox.getState() ); closeOnHaltCheckbox.addItemListener(this); closeOnHaltCheckbox.setFont(SANSSERIF); contentPanel.add( closeOnHaltCheckbox, ToyToolkit.createGridBagConstraints( 0, 4, 1, 1, 100.0, 1.0, GridBagConstraints.SOUTH, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 10), 0, 0 ) ); animatedIcon = new ToyAnimatedIcon(newImageManager); contentPanel.add( animatedIcon, ToyToolkit.createGridBagConstraints( 1, 0, 1, 5, 1.0, 1.0, GridBagConstraints.NORTHEAST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0 ) ); contentPanel.add( new ToySpacer(LABEL_WIDTH, 0), ToyToolkit.createGridBagConstraints( 0, 5, 2, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0 ) ); //center the false button Panel buttonPanel = new Panel(new GridLayout(2, 1, 0, 0)); contentPanel.add( buttonPanel, ToyToolkit.createGridBagConstraints( 0, 6, 2, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0 ) ); buttonPanel.add(new ToySpacer(80, 0)); falseButton = new Button("Abort"); falseButton.setActionCommand("false"); falseButton.setFont(SANSSERIF); falseButton.addActionListener(this); buttonPanel.add(falseButton); pack(); animatedIcon.start(); runner = new Thread(this); runner.start(); show(); runner = null; animatedIcon.finalize(); } //////////////////////////////////////////////////////////////////////////// // Implement Runnable public void run() { Thread thisThread = Thread.currentThread(); int stepsExecuted = 0; long startTime = System.currentTimeMillis(), elapsedTime, lastRefreshTime = 0; boolean firstStep; //wait for the dialog to be shown while (thisThread == runner && !isShowing()) { try { Thread.sleep(100); } catch (Exception e) { //whatever } } //then start iterating while (thisThread == runner) { firstStep = true; //do 100 steps unless something special happened while (thisThread == runner && (firstStep || stepsExecuted % 100 != 0) && !virtualMachine.isDone() && !virtualMachine.requiresInput()) { virtualMachine.step( uninitializedErrorEnabled, overflowErrorEnabled, outOfBoundsErrorEnabled ); firstStep = false; if (!virtualMachine.requiresInput()) stepsExecuted++; } //only refresh every second (or if something special happened) if (System.currentTimeMillis() - lastRefreshTime > 1000 || virtualMachine.isDone() || virtualMachine.requiresInput()) { refreshablePanel.refresh(); lastRefreshTime = System.currentTimeMillis(); } //only update the labels if the user can see them if (isShowing()) { elapsedTime = System.currentTimeMillis() - startTime; elapsedTimeLabel.setText( " Elapsed Time: " + elapsedTime / 1000 + "." + (elapsedTime % 1000) / 100 + (elapsedTime % 100 / 10) + (elapsedTime % 10) + " s" ); stepsExecutedLabel.setText(" Steps Executed: " + stepsExecuted); } //get input if necessary if (virtualMachine.requiresInput()) { if (!ToyPopup.askForInput(this, virtualMachine, true)) { //do this if the user aborted during the input request runner = null; animatedIcon.finalize(); removeAll(); dispose(); } } //stop if we're done if (virtualMachine.isDone()) runner = null; try { if (thisThread == runner) Thread.sleep(100); } catch (Exception e) { //whatever } } try { if (isShowing() && !closeOnHaltCheckbox.getState()) { if (virtualMachine.hasEncounteredError()) executingLabel.setText("A runtime error has occurred."); else executingLabel.setText("The program halted sucessfully."); falseButton.setLabel("OK"); animatedIcon.stop(); } else { runner = null; animatedIcon.finalize(); removeAll(); dispose(); } } catch (Exception e) { //whatever } } //////////////////////////////////////////////////////////////////////////// // Implement ActionListener public void actionPerformed(ActionEvent e) { if (e.getActionCommand().equals("true")) { response = true; removeAll(); dispose(); } if (e.getActionCommand().equals("false")) { response = false; removeAll(); dispose(); } if (e.getActionCommand().equals("open")) { Container containerCtr = getParent(); while (containerCtr != null && !(containerCtr instanceof Frame)) containerCtr = containerCtr.getParent(); if (containerCtr == null) return; FileDialog fileDialog = new FileDialog( (Frame)containerCtr, "Open Input File", FileDialog.LOAD ); fileDialog.setFile("*.txt"); fileDialog.show(); if (fileDialog.getFile() != null && fileDialog.getDirectory() != null) { try { FileReader file = new FileReader(fileDialog.getDirectory() + fileDialog.getFile()); int newChar; String textString = ""; char nameCharArray[]; //copy the file, character by character, into the current text do { newChar = file.read(); if (newChar != -1) textString += (char)newChar; } while (newChar != -1); file.close(); inputTextArea.setText(textString); } catch (Exception err) { err.printStackTrace(); ToyPopup.askUser( this, "File Reading Error", "An error occured when reading the file\n" + "\tAn error occured when reading the file. This probably occured because " + "your browser has a really strange security setting where it allows an " + "applet to open a file dialog box, but doesn't allow it to read the " + "selected file. Please follow the instructions on the launch page to " + "give this program the appropriate permissions.", "OK" ); } } } if (e.getActionCommand().equals("save")) { Container containerCtr = getParent(); while (containerCtr != null && !(containerCtr instanceof Frame)) containerCtr = containerCtr.getParent(); if (containerCtr == null) return; FileDialog fileDialog = new FileDialog( (Frame)containerCtr, "Save Input File As", FileDialog.SAVE ); //recommend a name fileDialog.setFile( "input.txt" ); fileDialog.show(); if (fileDialog.getFile() != null && fileDialog.getDirectory() != null) { try { FileWriter file = new FileWriter(fileDialog.getDirectory() + fileDialog.getFile()); //dump the program text string into the file file.write(inputTextArea.getText()); file.close(); } catch (Exception err) { err.printStackTrace(); ToyPopup.askUser( this, "File Writing Error", "An error occured when writing the file\n" + "\tAn error occured when reading the file. This probably occured because " + "your browser has a really strange security setting where it allows an " + "applet to open a file dialog box, but doesn't allow it to write to the " + "selected file. Please follow the instructions on the launch page to " + "give this program the appropriate permissions.", "OK" ); } } } } //////////////////////////////////////////////////////////////////////////// // Implement ItemListener public void itemStateChanged(ItemEvent e) { if (e.getSource() == closeOnHaltCheckbox) { closeExecutionCheckbox.setState( closeOnHaltCheckbox.getState() ); } if (e.getSource() == exampleTitleList) { for (int ctr = 0; ctr < MAX_PREVIEW_LINES; ctr++) exampleProgramLabels[ctr].setText(""); if (exampleTitleList.getSelectedIndex() < 0 || exampleTitleList.getSelectedIndex() >= examplePrograms.length) { trueButton.setEnabled(false); return; } else trueButton.setEnabled(true); String parseString = examplePrograms[exampleTitleList.getSelectedIndex()]; for (int ctr = 0; parseString.length() > 0 && ctr < MAX_PREVIEW_LINES; ctr++) { if (parseString.startsWith(ToyWorkspace.HEADER_BAR + "\n")) return; if (parseString.indexOf('\n') < 0) { exampleProgramLabels[ctr].setText(parseString); parseString = ""; } else { exampleProgramLabels[ctr].setText( parseString.substring( 0, parseString.indexOf('\n') ) ); parseString = parseString.substring( parseString.indexOf('\n') + 1 ); } } } } //////////////////////////////////////////////////////////////////////////// // Listen to window events public void processWindowEvent(WindowEvent e) { if (e.getID() == WindowEvent.WINDOW_CLOSING) { response = false; removeAll(); dispose(); } } }