/* PseudoCode Interpreted Language (PCIL): Part of the algoviz@vt collection of algorithm visualizations. Copyright (C) 2008 Brandon Malone, Frank Hadlock This file is part of the PseudoCode Interpreted Language. PseudoCode Interpreted Language 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 3 of the License, or (at your option) any later version. PseudoCode Interpreted Language 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 PseudoCode Interpreted Language. If not, see . */ /* * View.java * * Created on September 17, 2007, 9:30 PM */ package dynamicmvc; import java.awt.Component; import java.awt.Container; import java.awt.FlowLayout; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Stack; import javax.swing.JComponent; import javax.swing.JFileChooser; import javax.swing.JPanel; import syntacticanalysis.Function; import syntacticanalysis.PostfixToken; /** * * @author Compaq_Owner */ public class View extends javax.swing.JPanel implements ICheckBoxViewCaller { protected final static Object functionFlag = new Object(); protected final static Object variableFlag = new Object(); private static View theView; public static void updateView() { theView.render(true); } public static void updateAsk() { theView.refreshAsk(); } public static void repaintView() { theView.repaint(); } public static void updatePseudocode() { theView.resetPseudocode(); } public static void updateState(State state) { theView.state = state; } private State state; private DynamicController dController; Stack askStack; Stack differenceStack; // variables to skip over when rendering // need a stack to remember context when stepping into and out of functions Stack> hiddenVariables; protected ArrayList getCurrentHiddenVariables() { return hiddenVariables.peek(); } public void pushNewHiddenVariableContext() { hiddenVariables.push(new ArrayList()); } public void popHiddenVariableContext() { hiddenVariables.pop(); } /** Creates new form View */ public View() { initComponents(); state = new State(); dController = new DynamicController(this, state); askStack = new Stack(); differenceStack = new Stack(); this.lstPseudocode.setCellRenderer(new HTMLRenderer()); //render(); theView = this; } public void analyze(String pseudocodeFilePath) throws DynamicMVCException, IOException, Exception { // switch to input tab this.jTabbedPane2.setSelectedIndex(0); // input tab PostfixToken.resetID(); GraphInput.resetNames(); PrimitiveFactory.clearMemory(); GraphPanel.combinations = new HashMap>(); state = new State(); // initially, don't hide any variables hiddenVariables = new Stack>(); hiddenVariables.push(new ArrayList()); dController = new DynamicController(this, state); //dController.startExecution(pseudocodeFilePath, grammarFilePath); dController.startExecution(pseudocodeFilePath); askStack = new Stack(); differenceStack = new Stack(); resetPseudocode(); render(); } public State getState() { return state; } public void render() { render(false); } public void render(boolean updateAsk) { // bit of a hack, if it works if (this.askStack.size() > 0) { if (updateAsk) { updateAsk(); } else { try { showAskState(this.state.getPrimitive(this.dController.currentLineIndex()).deepCopy(new HashMap())); } catch (DynamicMVCException ex) { javax.swing.JOptionPane.showMessageDialog(null, "Encountered an exception while displaying the state:\n" + ex.getMessage()); ex.printStackTrace(); System.exit(-1); } } return; } renderInput(); renderStateVariables(); renderPseudocode(); this.btnStep.setEnabled(true); //this.btnSubmitAsk.setEnabled(false); this.repaint(); } private void renderInput() { this.pnlInput.removeAll(); PrimitiveFactory.clearUpdateNames(); for (PrimitivePointer input : state.getInputs()) { JComponent i = input.getEditComponent(); JComponent p = new JPanel();// Box.createVerticalBox(); FlowLayout l = (FlowLayout) p.getLayout(); l.setAlignment(FlowLayout.LEFT); p.add(i); this.pnlInput.add(p); } } private void renderStateVariables() { this.pnlState.removeAll(); ArrayList currentHiddenVariables = getCurrentHiddenVariables(); for (PrimitivePointer stateVariable : state.getStateVariables()) { // if the current hidden variables contains this variable's name, skip it if (currentHiddenVariables.contains(stateVariable.getName())) { continue; } JComponent s = stateVariable.getReadOnlyComponent(); JComponent p = new JPanel();// Box.createVerticalBox(); FlowLayout l = (FlowLayout) p.getLayout(); l.setAlignment(FlowLayout.LEFT); p.add(s); pnlState.add(p); } } public void resetPseudocode() { this.lstPseudocode.removeAll(); this.lstPseudocode.setListData(dController.getLines().toArray()); } public void renderPseudocode() { this.lstPseudocode.setSelectedIndex(dController.currentLineIndex()); } public void pushAskState(PrimitivePointer s) { askStack.push(s); } public void showAskState(PrimitivePointer ns) { // make sure there is something on the askStack // it could be empty if ask was placed before a block statement, such as an if or while // the reason this special case needs to be here is because // the grammar contains [nl] tokens for these statements // this is a hack fix if (askStack.empty()) { render(false); return; } // find the differences between s and the top thing on the ask stack PrimitiveStructure oldState = (PrimitiveStructure) (askStack.pop().dereference()); PrimitiveStructure newState = (PrimitiveStructure) (ns.dereference()); PrimitivePointer dp = PrimitiveFactory.create(PrimitiveStructure.pseudocodeTypeName(), "difference"); PrimitiveStructure differences = (PrimitiveStructure) dp.dereference(); PrimitivePointer adp = PrimitiveFactory.create(PrimitiveStructure.pseudocodeTypeName(), "actualDifferences"); PrimitiveStructure actualDifferences = (PrimitiveStructure) adp.dereference(); for (String n : newState.getDefinedProperties().keySet()) { PrimitivePointer otherP = oldState.getDefinedProperties().get(n); PrimitivePointer myP = newState.getDefinedProperties().get(n); // if the old state does not contain this variable, it needs to be updated if (otherP == null) { if (!myP.dereference().isNullable()) { PrimitivePointer newP = PrimitiveFactory.create(PrimitiveNull.pseudocodeTypeName(), myP.getName()); differences.set(myP.getName(), newP); actualDifferences.set(myP.getName(), myP); } continue; } try { // if the variables do not match, need to update the old variable // assume line only needs to be updated if the difference is more than 1 if (!myP.deepEquals(otherP) && !myP.getName().equalsIgnoreCase("line")) { // also, ensure the variables have the same properties myP.setEmptyProperties(otherP); differences.set(otherP.getName(), otherP); actualDifferences.set(myP.getName(), myP); } else if (myP.getName().equalsIgnoreCase("line")) { PrimitiveInteger oldLine = (PrimitiveInteger) otherP.dereference(); PrimitiveInteger newLine = (PrimitiveInteger) myP.dereference(); int ol = oldLine.getValue(); int nl = newLine.getValue(); // only ask about line when not just moving to the next line if (nl - ol != 1) { differences.set(otherP.getName(), otherP); actualDifferences.set(myP.getName(), myP); } } } catch (DynamicMVCException ex) { ex.printStackTrace(); } } askStack.push(dp); differenceStack.push(adp); updateAskState(); javax.swing.JOptionPane.showMessageDialog(null, "Please update the state correctly."); } public void refreshAsk() { PrimitivePointer p = readAsk(); askStack.push(p); updateAskState(); } public void updateAskState() { PrimitivePointer s = askStack.peek(); this.pnlAsk.removeAll(); Collection pointers = s.dereference().getDefinedProperties().values(); PrimitiveFactory.clearUpdateNames(); for (PrimitivePointer p : pointers) { JComponent i = p.getEditComponent(); JComponent c = new JPanel();// Box.createVerticalBox(); FlowLayout l = (FlowLayout) c.getLayout(); l.setAlignment(FlowLayout.LEFT); c.add(i); this.pnlAsk.add(c); } //this.btnStep.setEnabled(false); //this.btnSubmitAsk.setEnabled(true); this.repaint(); this.jTabbedPane2.setSelectedIndex(2); // 2 is the index of the ask pane } public void openFile() { jFileChooser1.setFileSelectionMode(JFileChooser.FILES_ONLY); if (this.jFileChooser1.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) { try { analyze(jFileChooser1.getSelectedFile().getCanonicalPath()); } catch (DynamicMVCException ex) { ex.printStackTrace(); javax.swing.JOptionPane.showMessageDialog(null, ex.getMessage()); } catch (IOException ex) { ex.printStackTrace(); javax.swing.JOptionPane.showMessageDialog(null, ex.getMessage()); } catch (Exception ex) { ex.printStackTrace(); javax.swing.JOptionPane.showMessageDialog(null, ex.getMessage()); } } } public void getFunctions() { ArrayList functions = dController.getFunctions(); ArrayList functionNames = new ArrayList(); ArrayList stepOverFunctions = dController.getStepOverFunctions(); for (Function function : functions) { functionNames.add(function.getName()); } CheckBoxView cbv = new CheckBoxView("Functions", "Please select the functions into which to step.", functionNames, stepOverFunctions, this, functionFlag); cbv.setVisible(true); } public void getVariables() { Collection variables = state.getStateVariables(); ArrayList variableNames = new ArrayList(); ArrayList hiddenVariableNames = this.getCurrentHiddenVariables(); for (PrimitivePointer p : variables) { variableNames.add(p.getName()); } CheckBoxView cbv = new CheckBoxView("Variables", "Please select the variables to display.", variableNames, hiddenVariableNames, this, variableFlag); cbv.setVisible(true); } public void checkAsk() { // read in the student's input for the differences PrimitivePointer inputDifferences = readAsk(); // and get the actual differences PrimitivePointer actualDifferences = differenceStack.pop(); // the only thing that may need to be changed is the value for "line" (number) // I have no idea why this was in here. // removing it doesn't seem to cause any harm 9/11/2008 /* int actualLineNumber = this.dController.currentLineIndex(); PrimitiveInteger lineNumber = null; try { lineNumber = (PrimitiveInteger) (actualDifferences.get("line").dereference()); } catch (DynamicMVCException ex) { ex.printStackTrace(); } lineNumber.setValue(actualLineNumber); */ // switch back to state this.jTabbedPane2.setSelectedIndex(1); // state tab // compare the input to the actual differences try { if (actualDifferences.deepEquals(inputDifferences)) { showMessage("Good Job! Press step to continue."); } else { showMessage("Incorrect. Error: \"" + DynamicController.errorMessage + "\". Press step to continue"); } render(); } catch (DynamicMVCException ex) { ex.printStackTrace(); } } /** This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ // //GEN-BEGIN:initComponents private void initComponents() { jFileChooser1 = new javax.swing.JFileChooser(); jSplitPane1 = new javax.swing.JSplitPane(); pnlPseudocode = new javax.swing.JPanel(); jScrollPane1 = new javax.swing.JScrollPane(); lstPseudocode = new javax.swing.JList(); btnInitialize = new javax.swing.JButton(); btnStep = new javax.swing.JButton(); pnlVariables = new javax.swing.JPanel(); jTabbedPane2 = new javax.swing.JTabbedPane(); jspInput = new javax.swing.JScrollPane(); pnlInput = new javax.swing.JPanel(); jspState = new javax.swing.JScrollPane(); pnlState = new javax.swing.JPanel(); jspAsk = new javax.swing.JScrollPane(); pnlAsk = new javax.swing.JPanel(); pnlPseudocode.setBorder(javax.swing.BorderFactory.createTitledBorder("Pseudocode")); pnlPseudocode.setPreferredSize(new java.awt.Dimension(200, 0)); jScrollPane1.setViewportView(lstPseudocode); btnInitialize.setText("Initialize"); btnInitialize.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseClicked(java.awt.event.MouseEvent evt) { btnInitializeMouseClicked(evt); } }); btnStep.setText("Step"); btnStep.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseClicked(java.awt.event.MouseEvent evt) { btnStepMouseClicked(evt); } }); javax.swing.GroupLayout pnlPseudocodeLayout = new javax.swing.GroupLayout(pnlPseudocode); pnlPseudocode.setLayout(pnlPseudocodeLayout); pnlPseudocodeLayout.setHorizontalGroup( pnlPseudocodeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(pnlPseudocodeLayout.createSequentialGroup() .addGroup(pnlPseudocodeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(pnlPseudocodeLayout.createSequentialGroup() .addComponent(btnInitialize) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(btnStep)) .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 132, Short.MAX_VALUE)) .addGap(10, 10, 10)) ); pnlPseudocodeLayout.setVerticalGroup( pnlPseudocodeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, pnlPseudocodeLayout.createSequentialGroup() .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 301, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(pnlPseudocodeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(btnInitialize) .addComponent(btnStep))) ); jSplitPane1.setLeftComponent(pnlPseudocode); javax.swing.GroupLayout pnlVariablesLayout = new javax.swing.GroupLayout(pnlVariables); pnlVariables.setLayout(pnlVariablesLayout); pnlVariablesLayout.setHorizontalGroup( pnlVariablesLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGap(0, 0, Short.MAX_VALUE) ); pnlVariablesLayout.setVerticalGroup( pnlVariablesLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGap(0, 0, Short.MAX_VALUE) ); jSplitPane1.setRightComponent(pnlVariables); pnlInput.setLayout(new javax.swing.BoxLayout(pnlInput, javax.swing.BoxLayout.Y_AXIS)); pnlInput.setBorder(javax.swing.BorderFactory.createTitledBorder("Input")); pnlInput.setAutoscrolls(true); jspInput.setViewportView(pnlInput); jTabbedPane2.addTab("Input", jspInput); pnlState.setLayout(new javax.swing.BoxLayout(pnlState, javax.swing.BoxLayout.Y_AXIS)); pnlState.setBorder(javax.swing.BorderFactory.createTitledBorder("State")); pnlState.setAutoscrolls(true); jspState.setViewportView(pnlState); jTabbedPane2.addTab("State", jspState); pnlAsk.setLayout(new javax.swing.BoxLayout(pnlAsk, javax.swing.BoxLayout.Y_AXIS)); pnlAsk.setBorder(javax.swing.BorderFactory.createTitledBorder("Ask")); jspAsk.setViewportView(pnlAsk); jTabbedPane2.addTab("Ask", jspAsk); jSplitPane1.setRightComponent(jTabbedPane2); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jSplitPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 395, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jSplitPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 359, Short.MAX_VALUE) ); }// //GEN-END:initComponents private void btnStepMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_btnStepMouseClicked try { // TODO add your handling code here: if (askStack.empty()) { dController.resumeExecution(); } else { checkAsk(); } } catch (DynamicMVCException ex) { ex.printStackTrace(); } }//GEN-LAST:event_btnStepMouseClicked private void btnInitializeMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_btnInitializeMouseClicked try { analyze(jFileChooser1.getSelectedFile().getCanonicalPath()); } catch (DynamicMVCException ex) { ex.printStackTrace(); } catch (IOException ex) { ex.printStackTrace(); } catch (Exception ex) { ex.printStackTrace(); } }//GEN-LAST:event_btnInitializeMouseClicked public PrimitivePointer readAsk() { PrimitivePointer p = askStack.pop(); Collection inputs = p.dereference().getDefinedProperties().values(); PrimitiveFactory.clearUpdateNames(); // find all of the inputs for(PrimitivePointer var : inputs) { // find the name of the component String componentName = var.dereference().getEditComponentWrapperName(); // look for this wrapper Component wrapper = pnlAsk; if (wrapper instanceof JComponent) { try { // update the variable var.populateFromEditComponentWrapper((JComponent)wrapper); } catch (DynamicMVCException ex) { ex.printStackTrace(); } } } return p; } public void readInputs() { // find all of the inputs Collection inputs = state.getInputs(); PrimitiveFactory.clearUpdateNames(); for(PrimitivePointer input : inputs) { // look for this wrapper Component wrapper = pnlInput;// getComponent(pnlInput, inputName); if (wrapper instanceof JComponent) { try { // update the variable input.populateFromEditComponentWrapper((JComponent)wrapper); } catch (DynamicMVCException ex) { ex.printStackTrace(); } try { // add a copy to the state variables PrimitivePointer copy = input.copy(); state.setStateVariable(input.getName(), copy); } catch (Exception ex) { ex.printStackTrace(); } } } this.jTabbedPane2.setSelectedIndex(1); // switch to the state tab } public static Component getComponent(String name) { return getComponent(theView.pnlAsk, name); } public static Component getComponent(Component container, String name) { if (container == null) { return null; } String n = container.getName(); // is it named? if (n != null) { // is this the control I am looking for? if (n.equalsIgnoreCase(name)) { return container; } } if (container instanceof Container) { Container c = (Container)container; // then look through all children for (int i=0; i stepOverFunctions = sender.getUncheckedOptions(); dController.setStepOverFunctions(stepOverFunctions); } else if (callerFlag == variableFlag) { ArrayList newHiddenVariables = sender.getUncheckedOptions(); // replace the current list of hidden variables with the new list hiddenVariables.pop(); hiddenVariables.push(newHiddenVariables); render(); } sender.dispose(); } public void cancelClicked(CheckBoxView sender, Object callerFlag) { sender.dispose(); } public void saveInput() { // read the input, serialize it, and save it to a file readInputs(); // state now has the inputs in it FileOutputStream fos = null; ObjectOutputStream out = null; try { fos = new FileOutputStream("state"); out = new ObjectOutputStream(fos); out.writeObject(state); out.close(); } catch (IOException ex) { ex.printStackTrace(); } } public void loadInput() { FileInputStream fis = null; ObjectInputStream in = null; try { fis = new FileInputStream("state"); in = new ObjectInputStream(fis); state = (State) in.readObject(); in.close(); } catch (IOException ex) { ex.printStackTrace(); } catch (ClassNotFoundException ex) { ex.printStackTrace(); } this.render(false); } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton btnInitialize; private javax.swing.JButton btnStep; private javax.swing.JFileChooser jFileChooser1; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JSplitPane jSplitPane1; private javax.swing.JTabbedPane jTabbedPane2; private javax.swing.JScrollPane jspAsk; private javax.swing.JScrollPane jspInput; private javax.swing.JScrollPane jspState; private javax.swing.JList lstPseudocode; private javax.swing.JPanel pnlAsk; private javax.swing.JPanel pnlInput; private javax.swing.JPanel pnlPseudocode; private javax.swing.JPanel pnlState; private javax.swing.JPanel pnlVariables; // End of variables declaration//GEN-END:variables }