/*
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
}