package edu.princeton.toy; import java.awt.*; import java.awt.event.*; import java.beans.*; import java.util.ArrayList; import java.util.List; import javax.swing.*; import javax.swing.border.*; import javax.swing.event.*; import edu.princeton.swing.*; import edu.princeton.toy.lang.*; /** * TSimMachinePane is a JPanel which acts the interface between the TVirtualMachine and the user * when Visual X-TOY is in Sim mode. * * @author btsang * @version 7.1 */ public class TSimMachinePane extends JLayeredPane { private static final String CLASS_STRING = TSimMachinePane.class.toString(); /** * The command to update the contents of the inputList with the stdin stream of the * virtualMachine. */ public static final String RESCALE_COMMAND = CLASS_STRING + "#rescaleCommand"; /** * The command to update the contents of the inputList with the stdin stream of the * virtualMachine. */ public static final String UPDATE_COMMAND = CLASS_STRING + "#updateCommand"; /** * The number of pc lights in the TSimMachinePane. */ public static final int PC_BIT_COUNT = 8; /** * The number of addr switches in the TSimMachinePane. */ public static final int ADDR_BIT_COUNT = 8; /** * The number of instr lights in the TSimMachinePane. */ public static final int INSTR_BIT_COUNT = 16; /** * The number of addr switches in the TSimMachinePane. */ public static final int DATA_BIT_COUNT = 16; /** * The color of the blue area in the TSimMachinePane. */ public static final Color BLUE_AREA_COLOR = new Color(80, 100, 120); /** * The border of the blue area in the TSimMachinePane. */ public static final Border BLUE_AREA_BORDER = new LineBorder(Color.black, 1); /** * The border of the resizing placeholder in the TSimMachinePane. */ public static final Border PLACEHOLDER_BORDER = new EtchedBorder(EtchedBorder.LOWERED); /** * The minimum scale which the TSimMachinePane can be scaled to. */ public static final int MIN_SCALE = 1; /** * The maxmimum scale to which the TSimMachinePane can be scaled. */ public static final int MAX_SCALE = TImageManager.MAX_SCALE[TImageManager.MACHINE_SCALED_IMAGE_GROUP]; /** * The scale used in determining the preferred size of the TSimMachinePane. */ public static final int PREFERRED_SCALE = 8; private static final Insets ZERO_INSETS = new Insets(0, 0, 0, 0); private static final Integer INTEGERS[] = new Integer[MAX_SCALE + 1]; private static final int UNSCALED_WIDTH = 80; private static final int UNSCALED_HEIGHT = 47; /** * Initialize the INTEGERS array. */ static { for (int ctr = 0; ctr <= MAX_SCALE; ctr++) INTEGERS[ctr] = new Integer(ctr); } private int newScale; private int scale; private Listener listener; private Runner runner; private TVirtualMachine virtualMachine; private List changeListeners; private JPanel bluePanel; private JPanel placeholderPanel; private JLabel placeholderLabel; private Action loadAction, lookAction, stepAction, runAction, enterAction, interruptAction, resetAction; private JButton loadButton, lookButton, stepButton, runButton, enterButton, interruptButton, resetButton; private JLabel inwaitLabel, inwaitLight; private JLabel readyLabel, readyLight; private JLabel pcLabel, pcLights[]; private JLabel addrLabel; private JToggleButton addrSwitches[]; private ButtonModel addrSwitchModels[]; private JLabel instrLabel, instrLights[]; private JLabel dataLabel; private JToggleButton dataSwitches[]; private ButtonModel dataSwitchModels[]; private JLabel stdoutLabel; private JLabel stdoutDigits[]; private TWordBuffer stdout; private Icon switchOffIcon; private Icon switchOnIcon; private Icon blankDigitIcon; private Icon digitIcons[]; /** * Creates a new TSimMachinePane. */ public TSimMachinePane(TVirtualMachine virtualMachine, Action loadAction, Action lookAction, Action stepAction, Action runAction, Action enterAction, Action interruptAction, Action resetAction) { super(); setLayout(null); setDoubleBuffered(true); if (virtualMachine == null) throw new NullPointerException(); this.virtualMachine = virtualMachine; runner = new Runner(); listener = new Listener(); virtualMachine.addChangeListener(listener); changeListeners = new ArrayList(); if (loadAction == null || lookAction == null || stepAction == null || runAction == null || enterAction == null || interruptAction == null || resetAction == null) throw new NullPointerException(); this.loadAction = loadAction; this.lookAction = lookAction; this.stepAction = stepAction; this.runAction = runAction; this.enterAction = enterAction; this.interruptAction = interruptAction; this.resetAction = resetAction; loadAction.addPropertyChangeListener(listener); lookAction.addPropertyChangeListener(listener); stepAction.addPropertyChangeListener(listener); runAction.addPropertyChangeListener(listener); enterAction.addPropertyChangeListener(listener); interruptAction.addPropertyChangeListener(listener); resetAction.addPropertyChangeListener(listener); bluePanel = new JPanel(null, false); bluePanel.setBackground(BLUE_AREA_COLOR); bluePanel.setBorder(BLUE_AREA_BORDER); bluePanel.add(loadButton = new JButton()); loadButton.setBorderPainted(false); loadButton.setContentAreaFilled(false); loadButton.setFocusPainted(false); loadButton.setMargin(ZERO_INSETS); loadButton.addActionListener(loadAction); loadButton.setEnabled(loadAction.isEnabled()); bluePanel.add(lookButton = new JButton()); lookButton.setBorderPainted(false); lookButton.setContentAreaFilled(false); lookButton.setFocusPainted(false); lookButton.setMargin(ZERO_INSETS); lookButton.addActionListener(lookAction); lookButton.setEnabled(lookAction.isEnabled()); bluePanel.add(stepButton = new JButton()); stepButton.setBorderPainted(false); stepButton.setContentAreaFilled(false); stepButton.setFocusPainted(false); stepButton.setMargin(ZERO_INSETS); stepButton.addActionListener(stepAction); stepButton.setEnabled(stepAction.isEnabled()); bluePanel.add(runButton = new JButton()); runButton.setBorderPainted(false); runButton.setContentAreaFilled(false); runButton.setFocusPainted(false); runButton.setMargin(ZERO_INSETS); runButton.addActionListener(runAction); runButton.setEnabled(runAction.isEnabled()); bluePanel.add(enterButton = new JButton()); enterButton.setBorderPainted(false); enterButton.setContentAreaFilled(false); enterButton.setFocusPainted(false); enterButton.setMargin(ZERO_INSETS); enterButton.addActionListener(enterAction); enterButton.setEnabled(enterAction.isEnabled()); bluePanel.add(interruptButton = new JButton()); interruptButton.setBorderPainted(false); interruptButton.setContentAreaFilled(false); interruptButton.setFocusPainted(false); interruptButton.setMargin(ZERO_INSETS); interruptButton.addActionListener(interruptAction); interruptButton.setEnabled(interruptAction.isEnabled()); bluePanel.add(resetButton = new JButton()); resetButton.setBorderPainted(false); resetButton.setContentAreaFilled(false); resetButton.setFocusPainted(false); resetButton.setMargin(ZERO_INSETS); resetButton.addActionListener(resetAction); resetButton.setEnabled(resetAction.isEnabled()); bluePanel.add(inwaitLabel = new JLabel()); bluePanel.add(inwaitLight = new JLabel()); bluePanel.add(readyLabel = new JLabel()); bluePanel.add(readyLight = new JLabel()); bluePanel.add(pcLabel = new JLabel()); pcLights = new JLabel[PC_BIT_COUNT]; for (int ctr = 0; ctr < PC_BIT_COUNT; ctr++) bluePanel.add(pcLights[ctr] = new JLabel()); bluePanel.add(addrLabel = new JLabel()); addrSwitches = new JToggleButton[ADDR_BIT_COUNT]; addrSwitchModels = new ButtonModel[ADDR_BIT_COUNT]; for (int ctr = 0; ctr < ADDR_BIT_COUNT; ctr++) { bluePanel.add(addrSwitches[ctr] = new JToggleButton()); addrSwitches[ctr].addActionListener(listener); addrSwitches[ctr].setBorderPainted(false); addrSwitches[ctr].setContentAreaFilled(false); addrSwitches[ctr].setFocusPainted(false); addrSwitches[ctr].setMargin(ZERO_INSETS); addrSwitchModels[ctr] = addrSwitches[ctr].getModel(); } bluePanel.add(instrLabel = new JLabel()); instrLights = new JLabel[INSTR_BIT_COUNT]; for (int ctr = 0; ctr < INSTR_BIT_COUNT; ctr++) bluePanel.add(instrLights[ctr] = new JLabel()); bluePanel.add(dataLabel = new JLabel()); dataSwitches = new JToggleButton[DATA_BIT_COUNT]; dataSwitchModels = new ButtonModel[DATA_BIT_COUNT]; for (int ctr = 0; ctr < DATA_BIT_COUNT; ctr++) { bluePanel.add(dataSwitches[ctr] = new JToggleButton()); dataSwitches[ctr].addActionListener(listener); dataSwitches[ctr].setBorderPainted(false); dataSwitches[ctr].setContentAreaFilled(false); dataSwitches[ctr].setFocusPainted(false); dataSwitches[ctr].setMargin(ZERO_INSETS); dataSwitchModels[ctr] = dataSwitches[ctr].getModel(); } bluePanel.add(stdoutLabel = new JLabel()); stdoutDigits = new JLabel[4]; bluePanel.add(stdoutDigits[3] = new JLabel()); bluePanel.add(stdoutDigits[2] = new JLabel()); bluePanel.add(stdoutDigits[1] = new JLabel()); bluePanel.add(stdoutDigits[0] = new JLabel()); add(bluePanel, new Integer(0)); placeholderPanel = new JPanel(); placeholderPanel.setBorder(PLACEHOLDER_BORDER); placeholderPanel.setVisible(false); add(placeholderPanel, new Integer(1)); placeholderLabel = new JLabel( "Visual X-TOY is curently resizing the graphics needed for sim mode...", SwingConstants.CENTER ); placeholderLabel.setOpaque(false); placeholderLabel.setVerticalTextPosition(SwingConstants.CENTER); placeholderLabel.setVisible(false); placeholderLabel.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); add(placeholderLabel, new Integer(2)); stdout = new TWordBuffer(); digitIcons = new Icon[TImageManager.MACHINE_SCALED_DIGITS.length]; scale = -1; doCommand( RESCALE_COMMAND, INTEGERS[TImageManager.ORIGINAL_IMAGE_SCALES[TImageManager.MACHINE_SCALED_IMAGE_GROUP]] ); setMinimumSize( new Dimension( UNSCALED_WIDTH * MIN_SCALE, UNSCALED_HEIGHT * MIN_SCALE ) ); setPreferredSize( new Dimension( UNSCALED_WIDTH * PREFERRED_SCALE, UNSCALED_HEIGHT * PREFERRED_SCALE ) ); enableEvents(AWTEvent.COMPONENT_EVENT_MASK); } /** * Adds a listener to monitor changes in the state of the switches. * * @param listener The listener to add to this pane. A null value will cause a * NullPointerException. */ public synchronized void addChangeListener(ChangeListener listener) { if (listener == null) throw new NullPointerException(); changeListeners.add(listener); } /** * Removes a listener from this machine. Nothing will happen if no match was found. * * @param listener The listener to remove from this pane. A null value will cause a * NullPointerException. */ public synchronized void removeChangeListener(ChangeListener listener) { if (listener == null) throw new NullPointerException(); changeListeners.remove(listener); } /** * Sets the virtualMachine attached to this TSimMachinePane. * * @param virtualMachine The virtualMachine to be attached to this TSimMachinePane. */ public void setVirtualMachine(TVirtualMachine virtualMachine) { if (virtualMachine == null) throw new NullPointerException(); if (this.virtualMachine == virtualMachine) return; this.virtualMachine.removeChangeListener(listener); virtualMachine.addChangeListener(listener); this.virtualMachine = virtualMachine; doCommand(UPDATE_COMMAND, null); } /** * Returns the virtualMachine attached to this TSimMachinePane. * * @return The virtualMachine attached to this TSimMachinePane. */ public TVirtualMachine getVirtualMachine() { return virtualMachine; } /** * Returns the TWord derived from the positions of the addr switches. * * @return The TWord derived from the positions of the addr switches. */ public TWord getAddr() { int value = 0; for (int ctr = 0; ctr < ADDR_BIT_COUNT; ctr++) { if (addrSwitchModels[ctr].isSelected()) value |= (1 << ctr); } return TWord.getWord((short)value); } /** * Returns the TWord derived from the positions of the data switches. * * @return The TWord derived from the positions of the data switches. */ public TWord getData() { int value = 0; for (int ctr = 0; ctr < DATA_BIT_COUNT; ctr++) { if (dataSwitchModels[ctr].isSelected()) value |= (1 << ctr); } return TWord.getWord((short)value); } /** * Fires a state changed event to all the listeners. */ protected void fireStateChanged() { if (!changeListeners.isEmpty()) { ChangeEvent e = new ChangeEvent(this); Object array[] = changeListeners.toArray(); for (int ctr = 0; ctr < array.length; ctr++) ((ChangeListener)array[ctr]).stateChanged(e); } } /** * Performs a command based on the argument. * * @param command A string representing the command. Note that pointer equality (not string * equality) is tested here, so it is important to use the string constants defined in this * class. An IllegalArgumentException will be thrown if the argument is invalid. * @return True iff the command was executed sucessfully. */ public synchronized boolean doCommand(String command, Object extraInfo) { //////////////////////////////////////////////////////////////////////////////////////////// if (command == RESCALE_COMMAND) { int scale = ((Integer)extraInfo).intValue(); if (scale < MIN_SCALE || scale > MAX_SCALE) throw new IllegalArgumentException(); if (scale == this.scale) { doCommand(UPDATE_COMMAND, null); return false; } Icon lightOffIcon = TImageManager.getIcon( TImageManager.MACHINE_SCALED_IMAGE_GROUP, scale, TImageManager.MACHINE_SCALED_LIGHT_OFF ); Icon lightOnIcon = TImageManager.getIcon( TImageManager.MACHINE_SCALED_IMAGE_GROUP, scale, TImageManager.MACHINE_SCALED_LIGHT_ON ); Icon switchOffIcon = TImageManager.getIcon( TImageManager.MACHINE_SCALED_IMAGE_GROUP, scale, TImageManager.MACHINE_SCALED_SWITCH_OFF ); this.switchOffIcon = switchOffIcon; Icon switchOnIcon = TImageManager.getIcon( TImageManager.MACHINE_SCALED_IMAGE_GROUP, scale, TImageManager.MACHINE_SCALED_SWITCH_ON ); this.switchOnIcon = switchOnIcon; blankDigitIcon = TImageManager.getIcon( TImageManager.MACHINE_SCALED_IMAGE_GROUP, scale, TImageManager.MACHINE_SCALED_DIGIT_BLANK ); for (int ctr = 0; ctr < TImageManager.MACHINE_SCALED_DIGITS.length; ctr++) { digitIcons[ctr] = TImageManager.getIcon( TImageManager.MACHINE_SCALED_IMAGE_GROUP, scale, TImageManager.MACHINE_SCALED_DIGITS[ctr] ); } loadButton.setDisabledIcon( TImageManager.getIcon( TImageManager.MACHINE_SCALED_IMAGE_GROUP, scale, TImageManager.MACHINE_SCALED_BUTTON_LOAD_OFF ) ); loadButton.setPressedIcon( TImageManager.getIcon( TImageManager.MACHINE_SCALED_IMAGE_GROUP, scale, TImageManager.MACHINE_SCALED_BUTTON_LOAD_OFF ) ); loadButton.setIcon( TImageManager.getIcon( TImageManager.MACHINE_SCALED_IMAGE_GROUP, scale, TImageManager.MACHINE_SCALED_BUTTON_LOAD_ON ) ); loadButton.setBounds(2 * scale, 2 * scale, 8 * scale, 3 * scale); lookButton.setDisabledIcon( TImageManager.getIcon( TImageManager.MACHINE_SCALED_IMAGE_GROUP, scale, TImageManager.MACHINE_SCALED_BUTTON_LOOK_OFF ) ); lookButton.setPressedIcon( TImageManager.getIcon( TImageManager.MACHINE_SCALED_IMAGE_GROUP, scale, TImageManager.MACHINE_SCALED_BUTTON_LOOK_OFF ) ); lookButton.setIcon( TImageManager.getIcon( TImageManager.MACHINE_SCALED_IMAGE_GROUP, scale, TImageManager.MACHINE_SCALED_BUTTON_LOOK_ON ) ); lookButton.setBounds(12 * scale, 2 * scale, 8 * scale, 3 * scale); stepButton.setDisabledIcon( TImageManager.getIcon( TImageManager.MACHINE_SCALED_IMAGE_GROUP, scale, TImageManager.MACHINE_SCALED_BUTTON_STEP_OFF ) ); stepButton.setPressedIcon( TImageManager.getIcon( TImageManager.MACHINE_SCALED_IMAGE_GROUP, scale, TImageManager.MACHINE_SCALED_BUTTON_STEP_OFF ) ); stepButton.setIcon( TImageManager.getIcon( TImageManager.MACHINE_SCALED_IMAGE_GROUP, scale, TImageManager.MACHINE_SCALED_BUTTON_STEP_ON ) ); stepButton.setBounds(22 * scale, 2 * scale, 8 * scale, 3 * scale); runButton.setDisabledIcon( TImageManager.getIcon( TImageManager.MACHINE_SCALED_IMAGE_GROUP, scale, TImageManager.MACHINE_SCALED_BUTTON_RUN_OFF ) ); runButton.setPressedIcon( TImageManager.getIcon( TImageManager.MACHINE_SCALED_IMAGE_GROUP, scale, TImageManager.MACHINE_SCALED_BUTTON_RUN_OFF ) ); runButton.setIcon( TImageManager.getIcon( TImageManager.MACHINE_SCALED_IMAGE_GROUP, scale, TImageManager.MACHINE_SCALED_BUTTON_RUN_ON ) ); runButton.setBounds(32 * scale, 2 * scale, 8 * scale, 3 * scale); enterButton.setDisabledIcon( TImageManager.getIcon( TImageManager.MACHINE_SCALED_IMAGE_GROUP, scale, TImageManager.MACHINE_SCALED_BUTTON_ENTER_OFF ) ); enterButton.setPressedIcon( TImageManager.getIcon( TImageManager.MACHINE_SCALED_IMAGE_GROUP, scale, TImageManager.MACHINE_SCALED_BUTTON_ENTER_OFF ) ); enterButton.setIcon( TImageManager.getIcon( TImageManager.MACHINE_SCALED_IMAGE_GROUP, scale, TImageManager.MACHINE_SCALED_BUTTON_ENTER_ON ) ); enterButton.setBounds(42 * scale, 2 * scale, 8 * scale, 3 * scale); interruptButton.setDisabledIcon( TImageManager.getIcon( TImageManager.MACHINE_SCALED_IMAGE_GROUP, scale, TImageManager.MACHINE_SCALED_BUTTON_INTERRUPT_OFF ) ); interruptButton.setPressedIcon( TImageManager.getIcon( TImageManager.MACHINE_SCALED_IMAGE_GROUP, scale, TImageManager.MACHINE_SCALED_BUTTON_INTERRUPT_OFF ) ); interruptButton.setIcon( TImageManager.getIcon( TImageManager.MACHINE_SCALED_IMAGE_GROUP, scale, TImageManager.MACHINE_SCALED_BUTTON_INTERRUPT_ON ) ); interruptButton.setBounds(52 * scale, 2 * scale, 8 * scale, 3 * scale); resetButton.setDisabledIcon( TImageManager.getIcon( TImageManager.MACHINE_SCALED_IMAGE_GROUP, scale, TImageManager.MACHINE_SCALED_BUTTON_RESET_OFF ) ); resetButton.setPressedIcon( TImageManager.getIcon( TImageManager.MACHINE_SCALED_IMAGE_GROUP, scale, TImageManager.MACHINE_SCALED_BUTTON_RESET_OFF ) ); resetButton.setIcon( TImageManager.getIcon( TImageManager.MACHINE_SCALED_IMAGE_GROUP, scale, TImageManager.MACHINE_SCALED_BUTTON_RESET_ON ) ); resetButton.setBounds(70 * scale, 2 * scale, 8 * scale, 3 * scale); inwaitLabel.setIcon( TImageManager.getIcon( TImageManager.MACHINE_SCALED_IMAGE_GROUP, scale, TImageManager.MACHINE_SCALED_LABEL_INWAIT ) ); inwaitLabel.setBounds(47 * scale, 7 * scale, 10 * scale, 2 * scale); inwaitLight.setDisabledIcon(lightOffIcon); inwaitLight.setIcon(lightOnIcon); inwaitLight.setBounds(42 * scale, 6 * scale, 4 * scale, 4 * scale); readyLabel.setIcon( TImageManager.getIcon( TImageManager.MACHINE_SCALED_IMAGE_GROUP, scale, TImageManager.MACHINE_SCALED_LABEL_READY ) ); readyLabel.setBounds(67 * scale, 7 * scale, 9 * scale, 2 * scale); readyLight.setDisabledIcon(lightOffIcon); readyLight.setIcon(lightOnIcon); readyLight.setBounds(62 * scale, 6 * scale, 4 * scale, 4 * scale); pcLabel.setIcon( TImageManager.getIcon( TImageManager.MACHINE_SCALED_IMAGE_GROUP, scale, TImageManager.MACHINE_SCALED_LABEL_PC ) ); pcLabel.setBounds(2 * scale, 11 * scale, 3 * scale, 2 * scale); for (int ctr = 0; ctr < PC_BIT_COUNT; ctr++) { pcLights[ctr].setDisabledIcon(lightOffIcon); pcLights[ctr].setIcon(lightOnIcon); pcLights[ctr].setBounds( (2 + 4 * ((PC_BIT_COUNT - ctr - 1) / 4 + PC_BIT_COUNT - ctr - 1)) * scale, 13 * scale, 4 * scale, 4 * scale ); } addrLabel.setIcon( TImageManager.getIcon( TImageManager.MACHINE_SCALED_IMAGE_GROUP, scale, TImageManager.MACHINE_SCALED_LABEL_ADDR ) ); addrLabel.setBounds(2 * scale, 17 * scale, 7 * scale, 2 * scale); for (int ctr = 0; ctr < ADDR_BIT_COUNT; ctr++) { addrSwitches[ctr].setIcon(switchOffIcon); addrSwitches[ctr].setSelectedIcon(switchOnIcon); addrSwitches[ctr].setPressedIcon( addrSwitchModels[ctr].isSelected()?switchOffIcon:switchOnIcon ); addrSwitches[ctr].setBounds( (2 + 4 * ((ADDR_BIT_COUNT - ctr - 1) / 4 + ADDR_BIT_COUNT - ctr - 1)) * scale, 19 * scale, 4 * scale, 8 * scale ); } instrLabel.setIcon( TImageManager.getIcon( TImageManager.MACHINE_SCALED_IMAGE_GROUP, scale, TImageManager.MACHINE_SCALED_LABEL_INSTR ) ); instrLabel.setBounds(2 * scale, 29 * scale, 8 * scale, 2 * scale); for (int ctr = 0; ctr < INSTR_BIT_COUNT; ctr++) { instrLights[ctr].setDisabledIcon(lightOffIcon); instrLights[ctr].setIcon(lightOnIcon); instrLights[ctr].setBounds( (2 + 4 * ((INSTR_BIT_COUNT - ctr - 1) / 4 + INSTR_BIT_COUNT - ctr - 1)) * scale, 31 * scale, 4 * scale, 4 * scale ); } dataLabel.setIcon( TImageManager.getIcon( TImageManager.MACHINE_SCALED_IMAGE_GROUP, scale, TImageManager.MACHINE_SCALED_LABEL_DATA ) ); dataLabel.setBounds(2 * scale, 35 * scale, 7 * scale, 2 * scale); for (int ctr = 0; ctr < DATA_BIT_COUNT; ctr++) { dataSwitches[ctr].setIcon(switchOffIcon); dataSwitches[ctr].setSelectedIcon(switchOnIcon); dataSwitches[ctr].setPressedIcon( dataSwitchModels[ctr].isSelected()?switchOffIcon:switchOnIcon ); dataSwitches[ctr].setBounds( (2 + 4 * ((DATA_BIT_COUNT - ctr - 1) / 4 + DATA_BIT_COUNT - ctr - 1)) * scale, 37 * scale, 4 * scale, 8 * scale ); } stdoutLabel.setIcon( TImageManager.getIcon( TImageManager.MACHINE_SCALED_IMAGE_GROUP, scale, TImageManager.MACHINE_SCALED_LABEL_STDOUT ) ); stdoutLabel.setBounds(42 * scale, 11 * scale, 10 * scale, 2 * scale); stdoutDigits[3].setBounds(42 * scale, 14 * scale, 8 * scale, 12 * scale); stdoutDigits[2].setBounds(51 * scale, 14 * scale, 8 * scale, 12 * scale); stdoutDigits[1].setBounds(60 * scale, 14 * scale, 8 * scale, 12 * scale); stdoutDigits[0].setBounds(69 * scale, 14 * scale, 8 * scale, 12 * scale); this.scale = scale; doCommand(UPDATE_COMMAND, null); return true; } //////////////////////////////////////////////////////////////////////////////////////////// if (command == UPDATE_COMMAND) { inwaitLight.setEnabled(virtualMachine.needsInput()); readyLight.setEnabled(!virtualMachine.isRunning() && !virtualMachine.needsInput()); short pcValue = virtualMachine.getProgramCtr().getValue(); for (int ctr = 0; ctr < PC_BIT_COUNT; ctr++) { pcLights[ctr].setEnabled(((pcValue >> ctr) & 1) != 0); } short instrValue = virtualMachine.getMem(pcValue & 0xFF).getValue(); for (int ctr = 0; ctr < INSTR_BIT_COUNT; ctr++) { instrLights[ctr].setEnabled(((instrValue >> ctr) & 1) != 0); } virtualMachine.getStdout(stdout); int size = stdout.getSize(); if (size > 0) { TWord lastWord = stdout.getWord(size - 1); stdoutDigits[3].setIcon(digitIcons[lastWord.getOp()]); stdoutDigits[2].setIcon(digitIcons[lastWord.getD()]); stdoutDigits[1].setIcon(digitIcons[lastWord.getS()]); stdoutDigits[0].setIcon(digitIcons[lastWord.getT()]); } else { stdoutDigits[3].setIcon(blankDigitIcon); stdoutDigits[2].setIcon(blankDigitIcon); stdoutDigits[1].setIcon(blankDigitIcon); stdoutDigits[0].setIcon(blankDigitIcon); } repaint(); return true; } throw new IllegalArgumentException(); } /** * Intercept ComponentEvents to do resize and move the bluePanel when this component is resized. */ protected void processComponentEvent(ComponentEvent e) { if (e.getID() == ComponentEvent.COMPONENT_RESIZED) { int width = getWidth(); int height = getHeight(); int scale = Math.min(width / UNSCALED_WIDTH, height / UNSCALED_HEIGHT); if (scale < MIN_SCALE) scale = MIN_SCALE; if (scale > MAX_SCALE) scale = MAX_SCALE; bluePanel.setBounds( width / 2 - UNSCALED_WIDTH * scale / 2, height / 2 - UNSCALED_HEIGHT * scale / 2, UNSCALED_WIDTH * scale, UNSCALED_HEIGHT * scale ); synchronized (this) { this.newScale = scale; if (!runner.isRunning) { if (!TImageManager.isPrepared(TImageManager.MACHINE_SCALED_IMAGE_GROUP, scale)) { bluePanel.setVisible(false); placeholderPanel.setBounds( width / 2 - UNSCALED_WIDTH * scale / 2, height / 2 - UNSCALED_HEIGHT * scale / 2, UNSCALED_WIDTH * scale, UNSCALED_HEIGHT * scale ); placeholderPanel.setVisible(true); placeholderLabel.setBounds(0, 0, width, height); placeholderLabel.setVisible(true); PSwingUtilities.paintWindowImmediately(this); runner.start(); } else { doCommand(RESCALE_COMMAND, INTEGERS[scale]); } } else { placeholderPanel.setBounds( width / 2 - UNSCALED_WIDTH * scale / 2, height / 2 - UNSCALED_HEIGHT * scale / 2, UNSCALED_WIDTH * scale, UNSCALED_HEIGHT * scale ); placeholderLabel.setBounds(0, 0, width, height); PSwingUtilities.paintWindowImmediately(this); } } } super.processComponentEvent(e); } /** * The Listener of a TBaseConverterPane pays attention to the changes in the PTextFields, and * fires off changes to the other PTextFields. * * @author btsang * @version 7.1 */ protected class Listener implements ActionListener, ChangeListener, PropertyChangeListener { /** * Implement ActionListener to listen for actions on the switches. */ public void actionPerformed(ActionEvent e) { JToggleButton button = ((JToggleButton)e.getSource()); button.setPressedIcon(button.getModel().isSelected()?switchOffIcon:switchOnIcon); fireStateChanged(); } /** * Implement ChangeListener to update the list whenever the virtual machine's state changes. */ public void stateChanged(ChangeEvent e) { doCommand(UPDATE_COMMAND, null); } /** * Implement PropertyChangeListener to update the state of the buttons whenever the * action's state changes. */ public void propertyChange(PropertyChangeEvent e) { if ("enabled".equals(e.getPropertyName())) { Object source = e.getSource(); if (source == loadAction) { loadButton.setEnabled(loadAction.isEnabled()); } else if (source == lookAction) { lookButton.setEnabled(lookAction.isEnabled()); } else if (source == stepAction) { stepButton.setEnabled(stepAction.isEnabled()); } else if (source == runAction) { runButton.setEnabled(runAction.isEnabled()); } else if (source == enterAction) { enterButton.setEnabled(enterAction.isEnabled()); } else if (source == interruptAction) { interruptButton.setEnabled(interruptAction.isEnabled()); } else if (source == resetAction) { resetButton.setEnabled(resetAction.isEnabled()); } } } } /** * Runner is a simple implementation of Runnable for the Thread started when the component's * size changes. * * @author btsang * @version 7.1 */ protected class Runner implements Runnable { protected boolean isRunning; private Thread thread; protected Runner() { isRunning = false; } /** * Causes the runner to start. This should only be called by a Thread which has * synchronized the TSimMachinePane and has checked that the Runner is not already running. */ public void start() { isRunning = true; thread = new Thread(this); thread.start(); } /** * Implement Runnable to run the TSimMachinePane. */ public void run() { int scale; while (true) { synchronized (TSimMachinePane.this) { scale = newScale; if (TImageManager.isPrepared(TImageManager.MACHINE_SCALED_IMAGE_GROUP, scale)) { doCommand(RESCALE_COMMAND, INTEGERS[scale]); placeholderPanel.setVisible(false); placeholderLabel.setVisible(false); bluePanel.setVisible(true); repaint(); isRunning = false; thread = null; return; } } TImageManager.prepare(TImageManager.MACHINE_SCALED_IMAGE_GROUP, scale); } } } }